分类存档: Java - 第2页

android自定义日期组件(拨动效果)

android自带的日期组件是通过TimeDialog,让用户上下调整来输入.但这样势必让用户需要点击某个按钮,弹出对话框后在选择.感觉不是非常的友好.

自己写了一个日期组件,可以通过手势在时间上拨动,达到调整数字的目的.

代码如下:

package com.zjhcsoft.mobi.android.widget;

import java.util.Calendar;

import java.util.GregorianCalendar;

import com.zjhcsoft.mobi.android.ui.R;

import android.app.DatePickerDialog;

import android.app.Dialog;

import android.content.Context;

import android.content.res.TypedArray;

import android.util.AttributeSet;

import android.util.Log;

import android.view.GestureDetector;

import android.view.MotionEvent;

import android.view.View;

import android.widget.DatePicker;

import android.widget.TextView;

/**

* 日期滚动组件

* @author Fred

*

*/

public class RotateTimeInput extends TextView {

    private static final String TAG = "RotateTimeInput";

    public static final String UP = "up";

    public static final String DOWN = "down";

    private int year;

    private int month;

    private int days;

    private Calendar currentDate;//当前时间

    private float fontSize = 13L;

    private GestureDetector ges;//手势接口实现

    private RotateTimeListener rotateTimeListener;

    private Dialog dataDialog;//日期选择器

    private boolean isMove = false;

    private boolean isFling = false;

    private boolean isScroll = false;

    //细粒度属性设置

    private float longClickFix = 0;//防止滑动和长按有冲突

    private float longClickNorm = 50;//区分滑动和长按标准差值,差值大于改值时,放弃长按事件

    private int scrollNorm;//设置scroll因子 ,scroll数大于默认值时,时间触发

    public RotateTimeInput(Context context, AttributeSet attrs) {

        super(context, attrs);

        initRotateWidget(context,attrs);

    }

    /**

    * 初始化控件时间

    * @param year 年

    * @param month 月-1

    * @param days 日

    */

    public void initByGivenDate(int year,int month,int days){

        this.year = year;

        this.month = month-1;

        this.days = days;

        currentDate = null;

        this.setText(formatTime());//设置默认值显示值

    }

    /**

    * 初始化RotateTime组件

    * @param context 应用上下文

    * @param attrs 配置属性

    */

    private void initRotateWidget(Context context,AttributeSet attrs){

        TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.RotateTimeInput);

        scrollNorm = a.getInt(R.styleable.RotateTimeInput_scrollNorm,8);

        a.recycle();

        //设置字体大小

        setTextSize(fontSize);

        //初始化当前时间

        this.setText(formatTime());//设置默认值显示值

        //增加轨迹事件

        ges = new GestureDetector(context,new TouchGesture(context));

        //鼠标手势触发

        this.setOnTouchListener(new OnTouchListener() {

            public boolean onTouch(View v, MotionEvent event) {

                if(event.getAction()==MotionEvent.ACTION_UP){

                    if(isMove&&isScroll&&!isFling){

                        longClickFix = 0;

                        rotateTimeListener();

                        isScroll = false;

                        isMove = false;

                    }

                }

                return ges.onTouchEvent(event);

            }

        });

    }

    /**

    * 时间格式化

    * @return

    */

    private String formatTime(){

        calculate();

        return new StringBuffer().append(year).append("年").append(month+1).append("月").append(days).append("日").toString();

    }

    /**

    * 日期递增

    */

    private void upDays(){

        currentDate.add(Calendar.DATE, 1);

        setText(formatTime());

    }

    /**

    * 日期减少

    */

    private void downDays(){

        currentDate.add(Calendar.DATE, -1);

        setText(formatTime());

    }

    /**

    * 调整时间

    * @param way 调整时间方向(RotateTimeInput.UP向前一天,RotateTimeInput.DOWN回退一天)

    */

    public void adjustDay(String way){

        if(way==UP){

            upDays();

            }else{

            downDays();

        }

        rotateTimeListener();

    }

    /**

    * 重新计算当前年月日天数

    */

    private void calculate(){

        if(currentDate==null){

            if(year!=0&&month!=0&&days!=0){

                this.currentDate = new GregorianCalendar(year, month, days);

                }else{

                this.currentDate = GregorianCalendar.getInstance();

            }

        }

        if (currentDate!=null){

            this.year = currentDate.get(Calendar.YEAR);

            this.month = currentDate.get(Calendar.MONTH);//Java中,月份从0开始

            this.days = currentDate.get(Calendar.DATE);

        }

    }

    /**

    * 创建Dialog对象,此处只有一个DataPick对象

    * @param context 应用上下文

    * @return

    */

    private Dialog initDialog(Context context){

        dataDialog = new DatePickerDialog(context,new DatePickerDialog.OnDateSetListener() {

            public void onDateSet(DatePicker view, int years, int monthOfYear,

            int dayOfMonth) {

                //DataPick用户锁定后

                currentDate.set(years, monthOfYear, dayOfMonth);

                setText(formatTime());

                rotateTimeListener();

            }

        },currentDate.get(Calendar.YEAR), currentDate.get(Calendar.MONTH), currentDate.get(Calendar.DATE));

        dataDialog.show();

        longClickFix = 0;//释放差值

        return dataDialog;

    }

    /**

    * Touch接口实现,监听用户鼠标轨迹

    * @author Fred

    *

    */

    class TouchGesture extends GestureDetector.SimpleOnGestureListener{

        private double scrollDistence=0;

        Context dialogContext;

        public TouchGesture(Context dialogContext){

            this.dialogContext = dialogContext;

        }

        @Override

        public void onLongPress(MotionEvent e) {

            if(longClickFix scrollNorm) {

                scrollDistence=0;

                if (distanceX<0){

                    upDays();

                    }else{

                    downDays();

                }

            }

            longClickFix = Math.abs(e2.getRawX() - e1.getRawX());

            return false;

        }

    }

    /**

    * 拨动事件

    * @param listener

    */

    public void setOnRotateTimeListener(RotateTimeListener listener){

        this.rotateTimeListener = listener;

    }

    private void rotateTimeListener(){

        calculate();

        if (rotateTimeListener!=null){

            rotateTimeListener.onRotateTime(this.year, this.month+1, this.days);

        }

    }

    class RotateFlyingThread extends Thread {

        private int ri;

        private int rp;

        private float af;

        private boolean stop = false;

        private int ic;

        public RotateFlyingThread(int rotateInterval, int rotatePeriod,

        float attenuateFactor, int increment) {

            ri = rotateInterval;

            rp = rotatePeriod;

            af = attenuateFactor;

            ic = increment;

        }

        public void stopRotate() {

            stop = true;

        }

        public void run() {

            int p = 0;

            Log.i("Rotating", String.format( "rotateInterval: %s, rotatePeriod: %s, attenuateFactor: %s, increment: %s,", ri, rp, af, ic));

            while ((p < rp) && !stop) {

                Log.i("Rotating", " ..." + RotateTimeInput.this.getText());

                RotateTimeInput.this.post(new Runnable() {

                    public void run() {

                        if (ic>0){

                            upDays();

                            }else{

                            downDays();

                        }

                    }

                });

                try {

                    Thread.sleep(ri);

                    } catch (InterruptedException e) {

                    e.printStackTrace();

                }

                ri += (int) (ri * (af / 10));

                p += ri;

            }

            rotateTimeListener();

            isFling = false;

            isMove = false;

            Log.i("Rotating", "stopped");

        }

    }

}

事件接口:

package com.fengsage.mobi.android.widget;

/**

* 拨动时间空间

* @author Fred

*

*/

public interface RotateTimeListener {

/**

* 当时间停下来的时候,开始触发事件

* @param year

* @param month 1--12

* @param days

*/

public void onRotateTime(int year,int month,int days);

}

最终效果如下:

在数字上面,用手左右来回拖动,时间也会跟着变动. 如果长按,则会弹出android标准的日期控件.

在android如何使用AsyncTask异步任务

最近项目中用到异步任务功能,网上搜罗了下资料,奈何国内的质量实在太低,依靠伟大的谷歌搜到很多国外的文章,写的非常的好,更好的在于没有copy paste的成分.

本文内容转自:http://www.brighthub.com/mobile/google-android/articles/82805.aspx

英语好的朋友请直接阅读原文.小弟不才,做个苦力当翻译

介绍

我们的Android应用越来越复杂,连接服务端,和web交互数据,存储大文件在android数据库中的同时显示进度条或者在通知栏显示通知. 我们如何能在抛开UI线程的情况下,边接受处理数据边用进度条展示呢?开始之前,必须知道什么是"UI线程"?

如果你熟悉"Thread"的概念. 那么你应该很容易明白异步任务. Android应用在处理的时候只有一个main主线程在运行.这个看上去像在任何地方只有一个任务. 如果你只有一个UI线程在工作,你就不能做一些复杂的事情,比如同时存储10000条记录,这个时候应用会停住,直到1000条记录存储完毕. 这不是一个好的方式. 在android你可以在一个应用里,同一时间运行多个线程. 举例:一个后台任务可以从服务端接受数据并且存储到本地数据库中.

如何对"Thread"概念有足够的了解,那么我们继续

现在我们可以开始了吗? 开始在后台执行任务? 这里我们还有几步工作要做.

一个古老的路线方法是使用Thread线程类,使用HandlersRunnables. 但是我们有更好的方式。使用AsyncTask

AsyncTask 类

让我来看看AsyncTask类的结构


				private class myBrightHubTask extends AsyncTask

				protected void onPreExecute(){

				}

				这个方式是在执行新线程前运行. 这里没有输入和输出的参数,所以这个可以初始化一些你认为必要的参数.

				protected Z doInBackground(X...x){

				}

				这是个非常重要的方法. 你可以在这里定义你需要的在后台执行的方法.这里开始是一个独立的线程在运行,而不是main线程. 这个方法接收一组对象集合,对象可以是在前继承AsyncTask的时候定义的X类型(你看到这个类的一开始我们继承的AsyncTask类了吗?这里的X就是这里的类型),默认是Object集合.

				protected void onProgressUpdate(Y y){

				}

				这个方法是在使用publishProgress()方法时触发,这个方法常用于显示一些在主线程中执行的进度条或者一些信息展示.比如当在执行一个后台任务的时候,前台做一个滚动条在滚动 ,

				protected void onPostExecute(Z z){

				}

这个方法在后台任务完成后执行,传入一个参数Z,也是前面定义的那个,你可以使用这个参数做一些结束任务时的处理,比如跳转intent或者其他的事情.

X,Y,Z的是什么类型?

我想你也可以从上面的结构中得出结论:

X – 运行后台任务的时候,需要传入的参数类型. 可以是一个对象的集合.

Y – 当你需要使用onProgressUpdate方法时,传入的参数类型

Z – 当后台任务完成时,需要传入数据处理的数据类型

如何使用这个异步任务呢?执行要执行下面2行代码.


				myBrightHubTask brightHubTask = new myBrightHubTask();

				brightHubTask.execute(x);

这里的输入参数是前面讲的X类型

一旦我们运行异步任务.你可以使用getStatus()方法获取它的状态


				brightHubTask.getStatus();

我们可以接受下面几个状态:

RUNNING – 任务处理中

PENDING – 任务还没有完成.

FINISHED – 任务结束.

提醒

需要注意的是:

  • 不用主动去调用onPreExecute, doInBackground and onPostExecute这个三个方法.这些方法会自动执行.

  • 你不能在另外一个AsyncTask或者线程中使用异步任务. 调用异步任务必须在UI主线程中使用.

  • onPostExecute 这个方法时在UI主线程中执行.这里你可以调用另外一个异步任务.

  • 输入参数可以设置一个Object集合,这样你就可以传入任意类型的对象

更多内容: http://www.brighthub.com/mobile/google-android/articles/82805.aspx#ixzz1GkXV8IT4

 

android单元测试(AndroidTestCase)

Android 单元测试基于JUnit开发.但是用起来并不容易

AndroidManifest.xml

确保你的应用加载了JUnint库,并配置AndroidMainifest.xml按照下面的方式.


				<?xml version="1.0" encoding="utf-8"?>

				<manifest

				xmlns:android="http://schemas.android.com/apk/res/android"

				package="com.example.app.tests" android:versionCode="1"

				android:versionName="1.0">

				<application>

				<uses-library android:name="android.test.runner" />

				</application>

				<uses-sdk android:minSdkVersion="3" />

				<instrumentation android:name="android.test.InstrumentationTestRunner"

				android:targetPackage="com.example.app" android:label="Tests for My App" />

				</manifest>

AllTests.java

编写测试代码入口.你可以把下面代码拷贝到任意工程去即可.


				package com.example.app;

				import junit.framework.Test;

				import junit.framework.TestSuite;

				import android.test.suitebuilder.TestSuiteBuilder;

				/**

				 * A test suite containing all tests for my application.

				 */

				public class AllTests extends TestSuite {

				    public static Test suite() {

				        return new TestSuiteBuilder(AllTests.class).includeAllPackagesUnderHere().build();

				    }

				}

				

SomeTests.java

编写单元测试,该测试集成AndroidTestCase父类. 记住所有的测试方法开头必须使用"test". 使用不同的assert方法来判断不同测试结果


				package com.example.app;

				import junit.framework.Assert;

				import android.test.AndroidTestCase;

				public class SomeTest extends AndroidTestCase {

				    public void testSomething() throws Throwable {

				       Assert.assertTrue(1 + 1 == 2);

				    }

				    public void testSomethingElse() throws Throwable {

				       Assert.assertTrue(1 + 1 == 3);

				    }

				}

				

运行单元测试

使用Eclipse的Run Junit Tests方法.选中测试工程,按右键,选择Run As…Android Junit Test.

或者输入下面命令:

adb shell am instrument -w com.example.app.tests/android.test.InstrumentationTestRunner

结果

你可以从Eclipse的console或命令行工具中看到结果. 完毕!

 

原文连接:http://marakana.com/tutorials/android/junit-test-example.html

Play非常不错的java敏捷框架

前几天了解了下Play这个框架. 原本1年前就对java web已经死心了的我,又有点重找回信心了.

不想去回忆java做web开发的痛苦了,框架间乱七八糟的组合,有无意义暂且不说,一个简单的增删改查,光写类就要写N个,出了错还得一个个debug过来.痛苦啊!所以年前就“背叛”Java 加入python阵营了. 用python做web真是优美,而且快速简单.至于很长时间对struts,webwork这种框架有点恶心.

感觉java除了高性能应用外,在web上简直就是糟糕透顶了. 然而不久前一次偶然的机会,让我了解了Play,彻底打破了我的想法,原来java也可以敏捷.也可以像python那样精简,快速.

这几天研究,做了官网上的Yabe例子,当然没做完(admin CRUD对现实意义不大),总结了下面几个优点:

  1. 自动编译,无需重启. 个人最欣赏的地方,总算可以摆脱一修改代码就要重启服务器的窘境了,事实上在调试阶段,重启服务器的时间远远大于修改代码所需的时间,时间大大浪费在毫无意义的等待上面了.
  2. 优美的URI映射. 貌似大部分敏捷框架,都在这里大下功夫.根据不同的URI,自动映射到不同的view层,别拿struts这种恶心人的uri映射来比,敏捷的uri映射更加灵活,更加强大.
  3. 简单的MVC层次. 不知道哪位规范了MVC模型,心意是好的,但是国内大部分web应用都瞎套了MVC,总之,我感觉struts之流引入MVC的概念不是简化了开发,而是大大增加了工作量,什么dao,daoimpl,server,serverimpl,view… 要多细可以写多细,然后我们自己问自己,真的有必要这么’细致’吗?敏捷告诉我们答案,mvc可以如此简单. Web技术的核心就是 “提交表单,操作数据库”.
  4. 强健的模板语言. 总所周知,一般java运用主要采用freemwark这种模板框架,究其原因还是JSTL这种标签表现力不够丰富,不够灵活,很难满足一般应用的需要.play模板语言重复吸取了ror,django这种脚本语言框架. 到处可以看到ror的影子.这点说不清楚,大家自己实际看一下就能明白,play的模板是多么的敏捷.
  5. Model. 最后写这点,因为这点也是java作为静态语言的无奈,不可能像python这样做成完美的充血模型,Play的model是基于JPA规范,也模仿动态语言写了增删改查的常见方法,但说到底这些都不是很好. Model也是个人觉得比较遗憾的地方了.

以上是这几天闲暇之余查看Play文档和做些例子的一些感受和想法. 粗浅的地方还望大家指正.

Creating a Custom JMX Client

http://java.sun.com/docs/books/tutorial/jmx/remote/custom.html

非常不错的实例.

很齐全,比国内网络上断章取义的文章好的多。

分享一个不错的分页Bean

/**
				* @author Fred Zhu
				* 分页辅助工具
				*/
				public class PageBean {

				private int currentPage = 1;// 当前页数
				private int totalPages = 0;// 总页数
				private int pageSize = 0;// 每页显示数
				private int totalRows = 0;// 总数据数
				private int startNum = 0;// 开始记录
				private int endNum = pageSize;//结束记录
				private int nextPage = 0;// 下一页
				private int previousPage = 0;// 上一页
				private boolean hasNextPage = false;// 是否有下一页
				private boolean hasPreviousPage = false;// 是否有前一页

				public PageBean(int pageSize, int currentPage, int totalRows) {

				this.pageSize = pageSize;
				this.currentPage = currentPage;
				this.totalRows = totalRows;

				//计算总页数
				if ((totalRows % pageSize) == 0) {
				totalPages = totalRows / pageSize;
				} else {
				totalPages = totalRows / pageSize + 1;
				}

				//是否有下一页
				if (currentPage >= totalPages) {
				hasNextPage = false;
				currentPage = totalPages;
				} else {
				hasNextPage = true;
				}

				//是否有上一页
				if (currentPage <= 1) {
				hasPreviousPage = false;
				currentPage = 1;
				} else {
				hasPreviousPage = true;
				}

				startNum = (currentPage - 1) * pageSize;//开始记录数

				if(totalPages-currentPage<1){
				endNum = totalRows;
				}else{
				endNum = currentPage*pageSize;
				}

				nextPage = currentPage + 1;//下一页页码

				previousPage = currentPage - 1;//上一页页码

				if (nextPage >= totalPages) {
				nextPage = totalPages;
				}

				if (previousPage <= 1) {
				previousPage = 1;
				}

				}

				public void refresh(int currentPage){
				this.currentPage = currentPage;
				startNum = (currentPage - 1) * pageSize;
				if(totalPages-currentPage<1){
				endNum = totalRows;
				}else{
				endNum = currentPage*pageSize;
				}
				}

				public boolean isHasNextPage() {

				return hasNextPage;

				}

				public boolean isHasPreviousPage() {

				return hasPreviousPage;

				}

				/**
				* @return the nextPage
				*/
				public int getNextPage() {
				return nextPage;
				}

				/**
				* @param nextPage
				*             the nextPage to set
				*/
				public void setNextPage(int nextPage) {
				this.nextPage = nextPage;
				}

				/**
				* @return the previousPage
				*/
				public int getPreviousPage() {
				return previousPage;
				}

				/**
				* @param previousPage
				*             the previousPage to set
				*/
				public void setPreviousPage(int previousPage) {
				this.previousPage = previousPage;
				}

				/**
				* @return the currentPage
				*/
				public int getCurrentPage() {
				return currentPage;
				}

				/**
				* @param currentPage
				*             the currentPage to set
				*/
				public void setCurrentPage(int currentPage) {
				this.currentPage = currentPage;
				}

				/**
				* @return the pageSize
				*/
				public int getPageSize() {
				return pageSize;
				}

				/**
				* @param pageSize
				*             the pageSize to set
				*/
				public void setPageSize(int pageSize) {
				this.pageSize = pageSize;
				}

				/**
				* @return the totalPages
				*/
				public int getTotalPages() {
				return totalPages;
				}

				/**
				* @param totalPages
				*             the totalPages to set
				*/
				public void setTotalPages(int totalPages) {
				this.totalPages = totalPages;
				}

				/**
				* @return the totalRows
				*/
				public int getTotalRows() {
				return totalRows;
				}

				/**
				* @param totalRows
				*             the totalRows to set
				*/
				public void setTotalRows(int totalRows) {
				this.totalRows = totalRows;
				}

				/**
				* @param hasNextPage
				*             the hasNextPage to set
				*/
				public void setHasNextPage(boolean hasNextPage) {
				this.hasNextPage = hasNextPage;
				}

				/**
				* @param hasPreviousPage
				*             the hasPreviousPage to set
				*/
				public void setHasPreviousPage(boolean hasPreviousPage) {
				this.hasPreviousPage = hasPreviousPage;
				}

				/**
				* @return the startNum
				*/
				public int getStartNum() {
				return startNum;
				}

				/**
				* @param startNum
				*             the startNum to set
				*/
				public void setStartNum(int startNum) {
				this.startNum = startNum;
				}

				public int getEndNum() {
				return endNum;
				}

				public void setEndNum(int endNum) {
				this.endNum = endNum;
				}
				}

性能瓶颈-项目中List的返回值

原文:http://www.javaeye.com/topic/569993

对于常见业务方法返回List对象时一般有二种方法:

1、返回含数据的数据的List对象,该对象可能为空

2、返回null

如下方法:

public List returnArray2(Object data){
if(data != null){
return (List) data;
}
return null;
}

一般使用时,

List list = xxxx.returnArray2(data);

这时候list都将具体指向一个内存,如果返回值为空时,list指向一个null的空内存,这时我们又要对list进行是否为null进行判断,量大时就可能对程序造成瓶颈。文章作者的解决方法是用Collections工具类的empty系列静态方法解决。

既如下代码:

public List returnArray2(Object data){
if(data == null){
return Collections.emptyList();
}
return (List) data;
}

此时如果为空返回的list将不存在为null的可能,并且empty系列方法是静态方法,所有引用都指向静态内存,不会生产和占用新的资源。不失为一个好的方法。

我们也可以自己编写自己的empty静态类,既每次都返回为空的静态的List、Map….对象。

我自己的一些理解,详细情况请大家访问原文和作者交流。

ActiveMq简单示例

最近,因工作需要对JMS进行了些了解和学习。不敢藏私,把些许经验和大家分享下,顺带自己也总结下,如有不足请指出。学习ActiveMq首先要对JMS规范有所了解。

JMS教程 这篇文章介绍的挺不错,虽然也是转载的不过好在排版还可以!呵呵!

要进行ActiveMq的开发,除了对概念要有所了解外,还要对JMS常用的接口有所了解,上面文档里也有描述。

下面2个程序,一个是向ActiveMq发送JMS消息,另一个是从ActiveMq里读取JMS消息!

package cn.fengsage.jms;

import java.util.Hashtable;

import javax.jms.*;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

/**
* @author Fred Zhu
*
*/
public class SenderTest {

private static final String DistDestQueName = "test";
private static final String JMS_FACTORY = "ConnectionFactory";

private Context jndiContext = null;
private QueueConnectionFactory qconFactory = null;
private QueueConnection qconn = null;
private QueueSession qsession = null;
private Queue queueDest = null;
private QueueSender qsender = null;

public void sendMessage(String msg) throws NamingException, JMSException {
jndiContext = this.getJndiContext();
qconFactory = (QueueConnectionFactory) jndiContext.lookup(JMS_FACTORY);
qconn = qconFactory.createQueueConnection();
qsession = qconn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
queueDest = (Queue) jndiContext.lookup(DistDestQueName);
qsender = qsession.createSender(queueDest);
TextMessage objMsg = null;
objMsg = qsession.createTextMessage();
qconn.start();
objMsg.setText(msg);
qsender.send(objMsg);
qconn.close();
qsender.close();

}

private Context getJndiContext() throws NamingException {
Hashtable properties = new Hashtable();
properties.put(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.activemq.jndi.ActiveMQInitialContextFactory");
properties.put(Context.PROVIDER_URL, "tcp://localhost:61616");
return new InitialContext(properties);
}

public static void main(String[] args) throws NamingException, JMSException {
SenderTest test = new SenderTest();
test.sendMessage("jms test");

}
}

package cn.fengsage.jms;

import java.util.Hashtable;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

/**
* @author Fred Zhu
*
*/
public class ReceiveTest {
private static final String DistDestQueName = "test";
private static final String JMS_FACTORY = "ConnectionFactory";

private Context jndiContext = null;
private QueueConnectionFactory qconFactory = null;
private QueueConnection qconn = null;
private QueueSession qsession = null;
private Queue queueDest = null;
private QueueReceiver qreceiver = null;

public void reveiveMessage() throws NamingException, JMSException {
jndiContext = this.getJndiContext();
qconFactory = (QueueConnectionFactory) jndiContext.lookup(JMS_FACTORY);
qconn = qconFactory.createQueueConnection();
qsession = qconn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
queueDest = (Queue) jndiContext.lookup(DistDestQueName);
qreceiver = qsession.createReceiver(queueDest);
qconn.start();
TextMessage message = (TextMessage) qreceiver.receive();
System.out.println(message.getText());
qconn.close();

}

private Context getJndiContext() throws NamingException {
Hashtable properties = new Hashtable();
properties.put(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.activemq.jndi.ActiveMQInitialContextFactory");
properties.put(Context.PROVIDER_URL, "tcp://localhost:61616");
return new InitialContext(properties);
}

public static void main(String[] args) throws NamingException, JMSException {
ReceiveTest test = new ReceiveTest();
test.reveiveMessage();
}
}

补充个官方的例子:http://activemq.apache.org/jndi-support.html

错误归纳:jquery formValidator

1、在和struts2框架做ajax验证时候,采用ajaxValidator方法!

url : “valEmail.action”, data:”email=”+$(“#email”).val();

这种形式传递不能把值传递到Service~~

解决方法:直接默认传递,即url : “valEmail.action”, 不构建任何字符串~由formValidator插件完成参数传递!然后在action里面通过String str = request.getParameter(“email”);得到传递的参数。

2、ajaxValidator乱码问题

由于前面一个问题导致不能加入参数,因此在传入中文后会有乱码出现!在action里面~~通过各种方式转换都不成功!

解决方法:打开formValidator.js文件,找到395行的

var parm = "clientid="+id+"&"+id+"="+encodeURIComponent(encodeURIComponent(srcjo.val()));

修改为

var parm = "clientid="+id+"&"+id+"="+escape(srcjo.val());
然后在服务端获取参数的时候String str = URLDecoder.decode(request.getParameter(“name”),”utf8″);转换即可

以上都是在源码和界面都采用utf8情况下!肯定有更好的解决方法!希望大家帮忙,集思广益!

Struts2实现财付通、支付宝、网银……

在线支付听起来是比较唬人,会吓到一片初学者,本人也曾是其中之一~~不过,只要认真研究平台提供的API和实例,就会发现在线支付不难~~

一般在线支付平台都已经封装的很好了!我们程序员所要做的只是实现接口对接而已!!

一般的在线支付都主要是2部分!!

1、请求(即把支付金额,支付帐户等相关信息给支付平台)

2、回调处理(在用户支付以后,支付平台会把相关信息又返回给本地系统,我们程序员要做的就是处理好这个步骤!)

下面我拿财付通做实例!实现下struts2+财付通 实现在线支付,strut2的相关配置就不做说明了!有兴趣的朋友可以去买本《struts2权威指南》看看,挺适合初学者的~

由于我要为后期实现各类支付方式打下基础。所以这里我会先写一个父类~封装一些商品通用属性。


				import java.util.Map;

				import com.ecfront.util.Constants;

				import com.ecfront.util.DateFormat;

				import com.opensymphony.xwork2.ActionContext;

				import com.opensymphony.xwork2.ActionSupport;

				import com.opensymphony.xwork2.Preparable;

				/**

				* 支付请求action

				* @author ZhuFeng

				*/

				public class PayAction extends ActionSupport implements Preparable {

				protected Object uId;// 用户ID

				protected Integer userId;// 用户ID

				protected long payId;// 订单ID

				/* 初始化用户ID */

				public void prepare() throws Exception {

				Map sessions = ActionContext.getContext().getSession();

				uId = sessions.get(Constants.USER_ID);

				if (uId != null) {

				userId = Integer.valueOf(uId.toString());

				}

				}

				//省略set、get

				}

这里是简单的把支付的订单ID、系统内部用户的ID、做了封装~

下面是财付通的请求action


				import javax.servlet.http.HttpServletRequest;

				import org.apache.struts2.interceptor.ServletRequestAware;

				import com.ecfront.pojo.Pay;

				import com.ecfront.service.PayService;

				import com.ecfront.util.Constants;

				import com.ecfront.util.PriceFormat;

				import com.opensymphony.xwork2.ActionSupport;

				import com.tenpay.bean.PayRequest;

				import com.tenpay.bean.PayResponse;

				import com.tenpay.helper.PayRequestHelper;

				import com.tenpay.helper.PayResponseHelper;

				import com.tenpay.util.TenpayUtil;

				/**

				* 财付通接口连接action

				* @author ZhuFeng

				*/

				public class TenPayAction extends PayAction implements ServletRequestAware {

				private HttpServletRequest request;// 请求环境变量

				private PayService payService;//注入订单服务层

				private String bargainor_id; // 商户号

				private String key; // 密钥

				private String return_url; // 回调地址

				private String sendUrl;//请求网关转发地址,因为struts2基于请求转发模式,此处利用jsp界面进行财付通网关的转发

				/*支付请求,封装了订单的相关信息*/

				public String request() {

				Pay pay = payService.getUserPay(userId, payId);

				String currTime = TenpayUtil.getCurrTime();

				String strRandom = TenpayUtil.buildRandom(4) + "";

				PayRequest payRequest = new PayRequest();

				payRequest.setAttach(String.valueOf(pay.getId()));// 自定义串,原样返回 存放订单ID

				payRequest.setBank_type("0"); // 银行类型 0:财付通

				payRequest.setBargainor_id(bargainor_id); // 商户号

				payRequest.setCmdno("1");// 任务代码 支付为1

				payRequest.setDate(currTime.substring(0, 8));// 商户日期 yyyyMMdd

				payRequest.setDesc("动脉商城(" + pay.getId() + ")");// 商品名称,以“动脉商城(订单编号)”为值

				payRequest.setFee_type("1");// 现金支付币种 1:人民币 其它币种暂不支持

				payRequest.setPurchaser_id("");// 买家财付通帐号,可以留空

				payRequest.setReturn_url(return_url);// 回调URL

				payRequest.setSp_billno(currTime + strRandom);// 商户订单号

				payRequest.setTotal_fee(pay.getPrice());// 订单总价,以分为单位

				payRequest.setTransaction_id(bargainor_id + currTime + strRandom);// 财付通交易单号

				String ip = TenpayUtil.toString(request.getRemoteAddr());// ip设置

				payRequest.setSpbill_create_ip(ip);

				PayRequestHelper helper = new PayRequestHelper(key, payRequest);

				sendUrl = helper.getSendUrl();

				return SUCCESS;

				}

				/*支付回调处理,对于正确支付则调用相应的业务逻辑,否则返回失败界面*/

				public String handler() {

				PayResponseHelper helper = new PayResponseHelper();

				helper.setKey(key);

				helper.setPayResponse(request);

				PayResponse payResponse = helper.getPayResponse();

				if ("0".equals(payResponse.getPay_result())) {

				// 支付成功,注意判断交易单重复性

				payService.modifPayOnline(

				Long.valueOf(payResponse.getAttach()), Constants.PAY_CAIFU,

				"", payResponse.getTotal_fee());

				// 注意金额问题,财付通以分为单位

				return SUCCESS;

				}

				return INPUT;

				}

注意下面几个属性~除了sendUrl以为,我都采用了IOC的方式,通过配置文件注入~(采用了spring做粘合)

bargainor_id; // 商户号 财付通申请的时候给你的

key; // 密钥

return_url; // 回调地址 这里相当重要,必须是一个http的绝对路径,最好是IP路径

sendUrl;//此处是一点小技巧,也是struts2实现的关键所在,用于把最后提交的地址保存到这个变量里面去!

下面是配置的相关信息!


				<action name="tenpay_request" class="tenPayAction" method="request">

				<result>../Pages/Buy/request.jsp</result>

				</action>

				<action name="tenpay_handler" class="tenPayAction" method="handler">

				<result type="redirect-action">../UserManager/mypay.action</result>

				</action>

tenpay_request.action是用于请求的路径~调用商品的request方法,把sendUrl提交给../pages/Buy/request.jsp页面~~这个页面里面就二句代码~~

<%

String obj = pageContext.getAttribute("sendUrl").toString();

response.sendRedirect(obj);

%>

就是把前面拼凑的sendUrl转向而已!

 

下面是请求处理,即交付款项以后,本地系统要做的事情~

本人的一点粗浅建议~可以分为2部~

1、对返回的数据包的数据提取重要信息,比如前面,我提交的时候,把订单的ID放到了自定义属性里面去。这时候我们要做的就是把这个订单ID拿回来

2、比对订单信息~上面拿回订单ID以后~在自己系统里面查找该ID符合的订单,并且比对该订单应付款和转向回来已付款~~如果都是正确的,则可以把该订单给完结~~否则,哪怕差1分钱,都放弃完成订单~~

有点乱~~~~算是给自己做个笔记,有兴趣的朋友在我博客首页加我QQ或发邮件 ,一起讨论讨论在线支付!!说实在,我上面的方法实在不咋地!!