微信支付java案例实现(基于springMVC框架demo)

2017年12月16日 08:38 | 5186次浏览 作者原创 版权保护

完整微信支付接入案例源码:点我下载案例源码

本章节由于要晒实现代码,所以篇幅有点长,读者可把代码复制到工程中,配置好参数即可实现,本案例站长亲测并实现。

整体工程项目实现说明:

1. 项目使用springmvc restful风格的,需要用到jar包请自行下载
2. 整个项目只需要修改com.tenpay.configure.WxPayConfig中的配置信息就行。

// appid
public static String APP_ID = "公众id";
// JSAPI接口中获取openid,审核后在公众平台开启开发模式后可查看
public static String APP_SECRET = "公众号中的秘钥";
// 受理商ID,身份标识
public static String MCH_ID = "商户id";
// 商户支付密钥Key,装完整数后,配置得到。32位长度
public static String KEY = "商户平台中配置证书,设置的秘钥";
// 异步回调地址
public static String NOTIFY_URL = "支付成功后的回调action";
public static String CHARTSET = "UTF-8";
// 加密方式
public static String SIGN_TYPE = "MD5";
// redirect_uri,微信授权重定向地址
public static String REDIRECT_URI;

static {
	try {
		REDIRECT_URI = URLEncoder.encode("微信授权成功后重定向的action", CHARTSET);
	} catch (UnsupportedEncodingException e) {
		e.printStackTrace();
	}
}

3. 项目核心类com.tenpay.action.WxPayAction
pay函数:支付前准备函数,从数据库获取订单号,查询订单金额,订单描述、openid、prepay_id等等。
notify函数:支付成功后异步回调函数。


一、新建基于springMVC框架的javaweb项目名字为wxPay

二、java代码实现

2.1 com.tenpay.action.WxPayAction代码

package com.tenpay.action;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jdom2.JDOMException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.tenpay.RequestHandler;
import com.tenpay.configure.WxPayConfig;
import com.tenpay.service.ServiceUtil;
import com.tenpay.util.MD5Util;
import com.tenpay.util.Sha1Util;
import com.tenpay.util.XMLUtil;

import net.sf.json.JSONObject;

/*******************************************************************************
 * <b>类名: WxPayAction.java</b> <br/>
 * 功能:微信支付,调用jsapi<br/>
 * 日期:<br/>
 * 
 * @author V型知识库 www.vxzsk.com
 * @version 1.0
 * 
 ******************************************************************************/
@Controller
@RequestMapping("/v_3")
public class WxPayAction {
	
	/**
	 * 微信客户端授权成功后根据redirect_uri参数调整到pay接口,去准备支付前信息接口
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("pay")
	public String order(HttpServletRequest request, HttpServletResponse response) throws Exception {
		/**
		 * 第一步:用户同意授权,根据参数,获取code
		 * 授权成功后返回的授权码,参考:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html#.E7.AC.AC.E4.B8.80.E6.AD.A5.EF.BC.9A.E7.94.A8.E6.88.B7.E5.90.8C.E6.84.8F.E6.8E.88.E6.9D.83.EF.BC.8C.E8.8E.B7.E5.8F.96code
		 */
		String code = request.getParameter("code");
		String state = request.getParameter("state");
		
		// state可以为任何含义,根据你前端需求,这里暂时叫商品id
		// 授权码、商品id
		System.out.println("code=" + code + ",state=" + state);
		
		/**
		 * 第二步:通过code换取网页授权access_token
		 * 根据授权码code获取access_token,参考:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html#.E7.AC.AC.E4.BA.8C.E6.AD.A5.EF.BC.9A.E9.80.9A.E8.BF.87code.E6.8D.A2.E5.8F.96.E7.BD.91.E9.A1.B5.E6.8E.88.E6.9D.83access_token
		 */
		// 下面就到了获取openid,这个代表用户id.
		// 获取openID
		String openid = ServiceUtil.getOpenId(code);
		// 生成随机字符串
		String noncestr = Sha1Util.getNonceStr();
		// 生成1970年到现在的秒数.
		String timestamp = Sha1Util.getTimeStamp();
		// 订单号,自定义生成规则,只要全局唯一就OK
		String out_trade_no = "NO" + System.currentTimeMillis() + "0001";
		// 订单金额,应该是根据state(商品id)从数据库中查询出来
		String order_price = String.valueOf(1);
		// 商品描述,应该是根据state(商品id)从数据库中查询出来
		String body = "商品描述,测试....";
		
		/**
		 * 第三步:统一下单接口
		 * 需要第二步生成的openid,参考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
		 */
		RequestHandler reqHandler = new RequestHandler(request, response);
		// 初始化 RequestHandler 类可以在微信的文档中找到.还有相关工具类
		reqHandler.init();
		// 执行统一下单接口 获得预支付id,一下是必填参数
		
		// 微信分配的公众账号ID(企业号corpid即为此appId)
		reqHandler.setParameter("appid", WxPayConfig.APP_ID); 
		// 微信支付分配的商户号
		reqHandler.setParameter("mch_id", WxPayConfig.MCH_ID); 
		// 终端设备号(门店号或收银设备ID),注意:PC网页或公众号内支付请传"WEB"
		reqHandler.setParameter("device_info", "WEB"); 
		// 随机字符串,不长于32位。推荐随机数生成算法
		reqHandler.setParameter("nonce_str", noncestr); 
		// 商品描述
		reqHandler.setParameter("body", body); 
		// 商家订单号
		reqHandler.setParameter("out_trade_no", out_trade_no); 
		// 商品金额,以分为单位
		reqHandler.setParameter("total_fee", order_price); 
		// APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。
		reqHandler.setParameter("spbill_create_ip", "123.57.58.123"); 
		// 下面的notify_url是用户支付成功后为微信调用的action 异步回调.
		reqHandler.setParameter("notify_url", WxPayConfig.NOTIFY_URL);
		// 交易类型,取值如下:JSAPI,NATIVE,APP,详细说明见参数规定
		reqHandler.setParameter("trade_type", "JSAPI");
		// ------------需要进行用户授权获取用户openid-------------
		reqHandler.setParameter("openid", openid); // 这个必填.
		/*
		 * <xml><appid>wx2421b1c4370ec43b</appid><attach>支付测试</attach><body>
		 * JSAPI支付测试</body><mch_id>10000100</mch_id><nonce_str>
		 * 1add1a30ac87aa2db72f57a2375d8fec</nonce_str><notify_url>http://wxpay.
		 * weixin.qq.com/pub_v2/pay/notify.v2.php</notify_url><openid>
		 * oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid><out_trade_no>1415659990</
		 * out_trade_no><spbill_create_ip>14.23.150.211</spbill_create_ip><
		 * total_fee>1</total_fee><trade_type>JSAPI</trade_type><sign>
		 * 0CB01533B8C1EF103065174F50BCA001</sign></xml>
		 */
		// 生成签名,并且转为xml
		String requestXml = reqHandler.getRequestXml();
		System.out.println("requestXml:" + requestXml);

		// 得到的预支付id
		String prepay_id = ServiceUtil.unifiedorder(requestXml);
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("appId", WxPayConfig.APP_ID);
		params.put("timeStamp", timestamp);
		params.put("nonceStr", noncestr);
		params.put("package", "prepay_id=" + prepay_id);
		params.put("signType", "MD5");

		System.out.println("params:" + JSONObject.fromObject(params).toString());
		
		// 生成支付签名,这个签名 给 微信支付的调用使用
		SortedMap<Object,Object> signMap = new TreeMap<Object,Object>();
        signMap.put("appId", WxPayConfig.APP_ID); 
        signMap.put("timeStamp", timestamp);
        signMap.put("nonceStr", noncestr);
        signMap.put("package", "prepay_id=" + prepay_id);
        signMap.put("signType", "MD5");
        
        // 微信支付签名
        String paySign = MD5Util.createSign(signMap, WxPayConfig.KEY);
        System.out.println("PaySIGN:" + paySign);
        
		//微信分配的公众账号ID(企业号corpid即为此appId)
		request.setAttribute("appId", WxPayConfig.APP_ID);
		// 时间戳
		request.setAttribute("timeStamp", timestamp); 
		// 随机字符串
		request.setAttribute("nonceStr", noncestr); 
		// 预支付id ,就这样的格式
		request.setAttribute("package", "prepay_id=" + prepay_id);
		// 加密格式
		request.setAttribute("signType", WxPayConfig.SIGN_TYPE); 
		// 微信支付签名
		request.setAttribute("paySign", paySign);
		return "pay";
	}

	/**
	 * 异步返回
	 */
	@RequestMapping("notify")
	public String notify(HttpServletRequest request, HttpServletResponse response) {
		try {

			InputStream inStream = request.getInputStream();
			ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
			byte[] buffer = new byte[1024];
			int len = 0;
			while ((len = inStream.read(buffer)) != -1) {
				outSteam.write(buffer, 0, len);
			}
			outSteam.close();
			inStream.close();
			String resultStr = new String(outSteam.toByteArray(), WxPayConfig.CHARTSET);
			Map<String, String> resultMap = XMLUtil.doXMLParse(resultStr);
			
			System.out.println("微信回调结果:" + resultMap.toString());
			
			String result_code = resultMap.get("result_code");
			String is_subscribe = resultMap.get("is_subscribe");
			String out_trade_no = resultMap.get("out_trade_no");
			String transaction_id = resultMap.get("transaction_id");
			String sign = resultMap.get("sign");
			String time_end = resultMap.get("time_end");
			String bank_type = resultMap.get("bank_type");
			String return_code = resultMap.get("return_code");
			// 签名验证
//			GenericValue userLogin = delegator.findOne("UserLogin", UtilMisc.toMap("userLoginId", "admin"), false);
			if (return_code.equals("SUCCESS")) {
				// 此处就是你的逻辑代码
				// 修改数据库支付状态
			}
			request.setAttribute("out_trade_no", out_trade_no);
			// 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
			response.getWriter().write(RequestHandler.setXML("SUCCESS", ""));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (JDOMException e) {
			e.printStackTrace();
		}
		return "notify";
	}
}

2.2 com.tenpay.configure.WxPayConfig 代码

package com.tenpay.configure;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

public class WxPayConfig {
	// appid
	public static String APP_ID = "";
	// JSAPI接口中获取openid,审核后在公众平台开启开发模式后可查看
	public static String APP_SECRET = "";
	// 受理商ID,身份标识
	public static String MCH_ID = "";
	// 商户支付密钥Key,装完整数后,配置得到。
	public static String KEY = "";
	// 异步回调地址
	public static String NOTIFY_URL = "https://www.vxzsk.com/wechat/v_3/notify";
	// 字符编码
	public static String CHARTSET = "UTF-8";
	// 加密方式
	public static String SIGN_TYPE = "MD5";
	// redirect_uri,微信授权重定向地址
	public static String REDIRECT_URI;
	
	static {
		try {
			REDIRECT_URI = URLEncoder.encode("https://www.vxzsk.com/wechat/v_3/pay", CHARTSET);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	}
}

2.3 com.tenpay.service.ServiceUtil 代码

package com.tenpay.service;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.tenpay.configure.WxPayConfig;
import com.tenpay.util.HttpClientUtil;
import com.tenpay.util.XMLUtil;

import net.sf.json.JSONObject;

/**
 * 自定义类,在官方文档中没有
 * 
 *
 */
public class ServiceUtil {
	private static final Log logger = LogFactory.getLog(ServiceUtil.class);
	
	/**
	 * 第二步:通过code换取网页授权access_token
	 * 根据授权码code获取access_token,参考:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html#.E7.AC.AC.E4.BA.8C.E6.AD.A5.EF.BC.9A.E9.80.9A.E8.BF.87code.E6.8D.A2.E5.8F.96.E7.BD.91.E9.A1.B5.E6.8E.88.E6.9D.83access_token
	 */
	public static String getOpenId(String code) {
		String openParam = "appid=" + WxPayConfig.APP_ID + "&secret=" + WxPayConfig.APP_SECRET + "&code=" + code + "&grant_type=authorization_code";
		String openJsonStr = HttpClientUtil.sendGET("https://api.weixin.qq.com/sns/oauth2/access_token", openParam);
		System.out.println("openJsonStr:"+openJsonStr);
		
		// 获取openid
		JSONObject openJson = JSONObject.fromObject(openJsonStr);
		String openid = openJson.getString("openid");
		return openid;
	} 
	
	/**
	 * 统一下单接口
	 * 参考文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
	 * @return
	 * @throws Exception 
	 */
	public static String unifiedorder(String requestXml) throws Exception{
		// 统一下单接口提交 xml格式
		URL orderUrl = new URL("https://api.mch.weixin.qq.com/pay/unifiedorder");
		HttpURLConnection conn = (HttpURLConnection) orderUrl.openConnection();
		conn.setConnectTimeout(30000); // 设置连接主机超时(单位:毫秒)
		conn.setReadTimeout(30000); // 设置从主机读取数据超时(单位:毫秒)
		conn.setDoOutput(true); // post请求参数要放在http正文内,顾设置成true,默认是false
		conn.setDoInput(true); // 设置是否从httpUrlConnection读入,默认情况下是true
		conn.setUseCaches(false); // Post 请求不能使用缓存
		// 设定传送的内容类型是可序列化的java对象(如果不设此项,在传送序列化对象时,当WEB服务默认的不是这种类型时可能抛java.io.EOFException)
		conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
		conn.setRequestMethod("POST");// 设定请求的方法为"POST",默认是GET
		conn.setRequestProperty("Content-Length", requestXml.length() + "");
		OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream(), WxPayConfig.CHARTSET);
		out.write(requestXml.toString());
		out.flush();
		out.close();
		if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
			return null;
		}
		// 获取响应内容体
		BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), WxPayConfig.CHARTSET));
		String line = "";
		StringBuffer strBuf = new StringBuffer();
		while ((line = in.readLine()) != null) {
			strBuf.append(line).append("\n");
		}
		in.close();
		System.out.println("result=========返回的xml=============" + strBuf.toString());
		Map<String, String> orderMap = XMLUtil.doXMLParse(strBuf.toString());
		System.out.println("orderMap===========================" + orderMap);
		
		// 获取
		String prepay_id = orderMap.get("prepay_id");
		return prepay_id;
	}
}

2.4 com.tenpay.util.HttpClientUtil 代码

package com.tenpay.util;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.HashMap;
import java.util.Map;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

import com.tenpay.configure.WxPayConfig;

/**
 * 
 *
 */
public class HttpClientUtil {
	
	public static final String SunX509 = "SunX509";
	public static final String JKS = "JKS";
	public static final String PKCS12 = "PKCS12";
	public static final String TLS = "TLS";
	
	public static String sendGET(String url, String param) {
		String result = "";// 访问返回结果
		BufferedReader read = null;// 读取访问结果

		try {
			// 创建url
			URL realurl = new URL(url + "?" + param);
			// 打开连接
			URLConnection connection = realurl.openConnection();
			// 设置通用的请求属性
			connection.setRequestProperty("accept", "*/*");
			connection.setRequestProperty("connection", "Keep-Alive");
			connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
			// 建立连接
			connection.connect();
			// 获取所有响应头字段
			// Map<String, List<String>> map = connection.getHeaderFields();
			// 遍历所有的响应头字段,获取到cookies等
			// for (String key : map.keySet()) {
			// System.out.println(key + "--->" + map.get(key));
			// }
			// 定义 BufferedReader输入流来读取URL的响应
			read = new BufferedReader(new InputStreamReader(connection.getInputStream(), WxPayConfig.CHARTSET));
			String line;// 循环读取
			while ((line = read.readLine()) != null) {
				result += line;
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (read != null) {// 关闭流
				try {
					read.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		return result;
	}
	
	/**
	 * get HttpURLConnection
	 * @param strUrl url��ַ
	 * @return HttpURLConnection
	 * @throws IOException
	 */
	public static HttpURLConnection getHttpURLConnection(String strUrl)
			throws IOException {
		URL url = new URL(strUrl);
		HttpURLConnection httpURLConnection = (HttpURLConnection) url
				.openConnection();
		return httpURLConnection;
	}
	
	/**
	 * get HttpsURLConnection
	 * @param strUrl url��ַ
	 * @return HttpsURLConnection
	 * @throws IOException
	 */
	public static HttpsURLConnection getHttpsURLConnection(String strUrl)
			throws IOException {
		URL url = new URL(strUrl);
		HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url
				.openConnection();
		return httpsURLConnection;
	}
	
	/**
	 * ��ȡ�����ѯ����url
	 * @param strUrl
	 * @return String
	 */
	public static String getURL(String strUrl) {

		if(null != strUrl) {
			int indexOf = strUrl.indexOf("?");
			if(-1 != indexOf) {
				return strUrl.substring(0, indexOf);
			} 
			
			return strUrl;
		}
		
		return strUrl;
		
	}
	
	/**
	 * ��ȡ��ѯ��
	 * @param strUrl
	 * @return String
	 */
	public static String getQueryString(String strUrl) {
		
		if(null != strUrl) {
			int indexOf = strUrl.indexOf("?");
			if(-1 != indexOf) {
				return strUrl.substring(indexOf+1, strUrl.length());
			} 
			
			return "";
		}
		
		return strUrl;
	}
	
	/**
	 * ��ѯ�ַ�ת����Map<br/>
	 * name1=key1&name2=key2&...
	 * @param queryString
	 * @return
	 */
	public static Map queryString2Map(String queryString) {
		if(null == queryString || "".equals(queryString)) {
			return null;
		}
		
		Map m = new HashMap();
		String[] strArray = queryString.split("&");
		for(int index = 0; index < strArray.length; index++) {
			String pair = strArray[index];
			HttpClientUtil.putMapByPair(pair, m);
		}
		
		return m;
		
	}
	
	/**
	 * �Ѽ�ֵ�����Map<br/>
	 * pair:name=value
	 * @param pair name=value
	 * @param m
	 */
	public static void putMapByPair(String pair, Map m) {
		
		if(null == pair || "".equals(pair)) {
			return;
		}
		
		int indexOf = pair.indexOf("=");
		if(-1 != indexOf) {
			String k = pair.substring(0, indexOf);
			String v = pair.substring(indexOf+1, pair.length());
			if(null != k && !"".equals(k)) {
				m.put(k, v);
			}
		} else {
			m.put(pair, "");
		}
	}
	
	/**
	 * BufferedReaderת����String<br/>
	 * ע��:���ر���Ҫ���д���
	 * @param reader
	 * @return String
	 * @throws IOException
	 */
	public static String bufferedReader2String(BufferedReader reader) throws IOException {
		StringBuffer buf = new StringBuffer();
		String line = null;
		while( (line = reader.readLine()) != null) {
			buf.append(line);
			buf.append("\r\n");
		}
				
		return buf.toString();
	}
	
	/**
	 * �������<br/>
	 * ע��:���ر���Ҫ���д���
	 * @param out
	 * @param data
	 * @param len
	 * @throws IOException
	 */
	public static void doOutput(OutputStream out, byte[] data, int len)
			throws IOException {
		int dataLen = data.length;
		int off = 0;
		while (off < data.length) {
			if (len >= dataLen) {
				out.write(data, off, dataLen);
				off += dataLen;
			} else {
				out.write(data, off, len);
				off += len;
				dataLen -= len;
			}

			// ˢ�»�����
			out.flush();
		}

	}
	
	/**
	 * ��ȡSSLContext
	 * @param trustFile 
	 * @param trustPasswd
	 * @param keyFile
	 * @param keyPasswd
	 * @return
	 * @throws NoSuchAlgorithmException 
	 * @throws KeyStoreException 
	 * @throws IOException 
	 * @throws CertificateException 
	 * @throws UnrecoverableKeyException 
	 * @throws KeyManagementException 
	 */
	public static SSLContext getSSLContext(
			FileInputStream trustFileInputStream, String trustPasswd,
			FileInputStream keyFileInputStream, String keyPasswd)
			throws NoSuchAlgorithmException, KeyStoreException,
			CertificateException, IOException, UnrecoverableKeyException,
			KeyManagementException {

		// ca
		TrustManagerFactory tmf = TrustManagerFactory.getInstance(HttpClientUtil.SunX509);
		KeyStore trustKeyStore = KeyStore.getInstance(HttpClientUtil.JKS);
		trustKeyStore.load(trustFileInputStream, HttpClientUtil
				.str2CharArray(trustPasswd));
		tmf.init(trustKeyStore);

		final char[] kp = HttpClientUtil.str2CharArray(keyPasswd);
		KeyManagerFactory kmf = KeyManagerFactory.getInstance(HttpClientUtil.SunX509);
		KeyStore ks = KeyStore.getInstance(HttpClientUtil.PKCS12);
		ks.load(keyFileInputStream, kp);
		kmf.init(ks, kp);

		SecureRandom rand = new SecureRandom();
		SSLContext ctx = SSLContext.getInstance(HttpClientUtil.TLS);
		ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), rand);

		return ctx;
	}
	
	/**
	 * ��ȡCA֤����Ϣ
	 * @param cafile CA֤���ļ�
	 * @return Certificate
	 * @throws CertificateException
	 * @throws IOException
	 */
	public static Certificate getCertificate(File cafile)
			throws CertificateException, IOException {
		CertificateFactory cf = CertificateFactory.getInstance("X.509");
		FileInputStream in = new FileInputStream(cafile);
		Certificate cert = cf.generateCertificate(in);
		in.close();
		return cert;
	}
	
	/**
	 * �ַ�ת����char����
	 * @param str
	 * @return char[]
	 */
	public static char[] str2CharArray(String str) {
		if(null == str) return null;
		
		return str.toCharArray();
	}
	
	/**
	 * �洢ca֤���JKS��ʽ
	 * @param cert
	 * @param alias
	 * @param password
	 * @param out
	 * @throws KeyStoreException
	 * @throws NoSuchAlgorithmException
	 * @throws CertificateException
	 * @throws IOException
	 */
	public static void storeCACert(Certificate cert, String alias,
			String password, OutputStream out) throws KeyStoreException,
			NoSuchAlgorithmException, CertificateException, IOException {
		KeyStore ks = KeyStore.getInstance("JKS");

		ks.load(null, null);

		ks.setCertificateEntry(alias, cert);

		// store keystore
		ks.store(out, HttpClientUtil.str2CharArray(password));

	}
	
	public static InputStream String2Inputstream(String str) {
		return new ByteArrayInputStream(str.getBytes());
	}
	
	/**
	 * InputStreamת����Byte
	 * ע��:���ر���Ҫ���д���
	 * @param in
	 * @return byte
	 * @throws Exception
	 */
	public static byte[] InputStreamTOByte(InputStream in) throws IOException{  
		
		int BUFFER_SIZE = 4096;  
		ByteArrayOutputStream outStream = new ByteArrayOutputStream(); 
        byte[] data = new byte[BUFFER_SIZE];  
        int count = -1;  
        
        while((count = in.read(data,0,BUFFER_SIZE)) != -1)  
            outStream.write(data, 0, count);  
          
        data = null;  
        byte[] outByte = outStream.toByteArray();
        outStream.close();
        
        return outByte;  
    } 
	
	/**
	 * InputStreamת����String
	 * ע��:���ر���Ҫ���д���
	 * @param in
	 * @param encoding ����
	 * @return String
	 * @throws Exception
	 */
	public static String InputStreamTOString(InputStream in,String encoding) throws IOException{  

        return new String(InputStreamTOByte(in),encoding);
        
    }
    

}

2.5 com.tenpay.util.JsonUtil

package com.tenpay.util;

import net.sf.json.JSONObject;

public class JsonUtil {

	public static String getJsonValue(String rescontent, String key) {
		JSONObject jsonObject;
		String v = null;
		try {
			jsonObject = JSONObject.fromObject(rescontent);
			v = jsonObject.getString(key);
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		return v;
	}
}

2.6  com.tenpay.util.MD5Util

package com.tenpay.util;

import java.security.MessageDigest;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;

import com.tenpay.configure.WxPayConfig;

public class MD5Util {

	@SuppressWarnings("rawtypes")
	public static String createSign(SortedMap<Object, Object> parameters, String key) {
		StringBuffer sb = new StringBuffer();
		Set es = parameters.entrySet();// 所有参与传参的参数按照accsii排序(升序)
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			Object v = entry.getValue();
			if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + key);
		String sign = MD5Util.MD5Encode(sb.toString(), WxPayConfig.CHARTSET).toUpperCase();
		return sign;
	}

	private static String byteArrayToHexString(byte b[]) {
		StringBuffer resultSb = new StringBuffer();
		for (int i = 0; i < b.length; i++)
			resultSb.append(byteToHexString(b[i]));

		return resultSb.toString();
	}

	private static String byteToHexString(byte b) {
		int n = b;
		if (n < 0)
			n += 256;
		int d1 = n / 16;
		int d2 = n % 16;
		return hexDigits[d1] + hexDigits[d2];
	}

	public static String MD5Encode(String origin, String charsetname) {
		String resultString = null;
		try {
			resultString = new String(origin);
			MessageDigest md = MessageDigest.getInstance("MD5");
			if (charsetname == null || "".equals(charsetname))
				resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
			else
				resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
		} catch (Exception exception) {
		}
		return resultString;
	}

	private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d",
			"e", "f" };
}

2.7 com.tenpay.util.Sha1Util

package com.tenpay.util;

import java.security.MessageDigest;
import java.util.Random;

import com.tenpay.configure.WxPayConfig;

public class Sha1Util {
	public static String getNonceStr() {
		Random random = new Random();
		return MD5Util.MD5Encode(String.valueOf(random.nextInt(10000)), WxPayConfig.CHARTSET);
	}

	public static String getTimeStamp() {
		return String.valueOf(System.currentTimeMillis() / 1000);
	}

	public static String getSha1(String str) {
		if (str == null || str.length() == 0) {
			return null;
		}

		char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
				'a', 'b', 'c', 'd', 'e', 'f' };

		try {
			MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
			mdTemp.update(str.getBytes());

			byte[] md = mdTemp.digest();
			int j = md.length;
			char buf[] = new char[j * 2];
			int k = 0;
			for (int i = 0; i < j; i++) {
				byte byte0 = md[i];
				buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
				buf[k++] = hexDigits[byte0 & 0xf];
			}
			return new String(buf);
		} catch (Exception e) {
			return null;
		}
	}

}

2.8 com.tenpay.util.XMLUtil

package com.tenpay.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.io.ByteArrayInputStream;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

import com.tenpay.configure.WxPayConfig;

/**
 * 
 *
 */
public class XMLUtil {

	/**
	 * ����xml,���ص�һ��Ԫ�ؼ�ֵ�ԡ�����һ��Ԫ�����ӽڵ㣬��˽ڵ��ֵ���ӽڵ��xml��ݡ�
	 * @param strxml
	 * @return
	 * @throws JDOMException
	 * @throws IOException
	 */
	public static Map doXMLParse(String strxml) throws JDOMException, IOException {
		strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");

		if(null == strxml || "".equals(strxml)) {
			return null;
		}
		
		Map m = new HashMap();
		
		InputStream in = new ByteArrayInputStream(strxml.getBytes(WxPayConfig.CHARTSET));
		SAXBuilder builder = new SAXBuilder();
		Document doc = builder.build(in);
		Element root = doc.getRootElement();
		List list = root.getChildren();
		Iterator it = list.iterator();
		while(it.hasNext()) {
			Element e = (Element) it.next();
			String k = e.getName();
			String v = "";
			List children = e.getChildren();
			if(children.isEmpty()) {
				v = e.getTextNormalize();
			} else {
				v = XMLUtil.getChildrenText(children);
			}
			
			m.put(k, v);
		}
		
		//�ر���
		in.close();
		
		return m;
	}
	
	/**
	 * ��ȡ�ӽ���xml
	 * @param children
	 * @return String
	 */
	public static String getChildrenText(List children) {
		StringBuffer sb = new StringBuffer();
		if(!children.isEmpty()) {
			Iterator it = children.iterator();
			while(it.hasNext()) {
				Element e = (Element) it.next();
				String name = e.getName();
				String value = e.getTextNormalize();
				List list = e.getChildren();
				sb.append("<" + name + ">");
				if(!list.isEmpty()) {
					sb.append(XMLUtil.getChildrenText(list));
				}
				sb.append(value);
				sb.append("</" + name + ">");
			}
		}
		
		return sb.toString();
	}
	
	/**
	 * ��ȡxml�����ַ�
	 * @param strxml
	 * @return
	 * @throws IOException 
	 * @throws JDOMException 
	 */
	public static String getXMLEncoding(String strxml) throws JDOMException, IOException {
		InputStream in = HttpClientUtil.String2Inputstream(strxml);
		SAXBuilder builder = new SAXBuilder();
		Document doc = builder.build(in);
		in.close();
		return (String)doc.getProperty("encoding");
	}
	
	
}

2.9 com.tenpay.RequestHandler

package com.tenpay;


import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.tenpay.configure.WxPayConfig;
import com.tenpay.util.MD5Util;

/**

 *
 */
public class RequestHandler {
	
	/** ���url��ַ */
	private String gateUrl;
	
	/** ��Կ */
	private String key;
	
	/** ����IJ��� */
	private SortedMap parameters;
	
	/** debug��Ϣ */
	private String debugInfo;
	
	protected HttpServletRequest request;
	
	protected HttpServletResponse response;
	
	/**
	 * ���캯��
	 * @param request
	 * @param response
	 */
	public RequestHandler(HttpServletRequest request, HttpServletResponse response) {
		this.request = request;
		this.response = response;
		
		this.gateUrl = "https://gw.tenpay.com/gateway/pay.htm";
		this.key = "";
		this.parameters = new TreeMap();
		this.debugInfo = "";
	}
	
	/**
	*��ʼ������
	*/
	public void init() {
		//nothing to do
	}

	/**
	*��ȡ��ڵ�ַ,�������ֵ
	*/
	public String getGateUrl() {
		return gateUrl;
	}

	/**
	*������ڵ�ַ,�������ֵ
	*/
	public void setGateUrl(String gateUrl) {
		this.gateUrl = gateUrl;
	}

	/**
	*��ȡ��Կ
	*/
	public String getKey() {
		return key;
	}

	/**
	*������Կ
	*/
	public void setKey(String key) {
		this.key = key;
	}
	
	/**
	 * ��ȡ����ֵ
	 * @param parameter �������
	 * @return String 
	 */
	public String getParameter(String parameter) {
		String s = (String)this.parameters.get(parameter); 
		return (null == s) ? "" : s;
	}
	
	/**
	 * ���ò���ֵ
	 * @param parameter �������
	 * @param parameterValue ����ֵ
	 */
	public void setParameter(String parameter, String parameterValue) {
		String v = "";
		if(null != parameterValue) {
			v = parameterValue.trim();
		}
		this.parameters.put(parameter, v);
	}
	
	/**
	 * �������еIJ���
	 * @return SortedMap
	 */
	public SortedMap getAllParameters() {		
		return this.parameters;
	}

	/**
	*��ȡdebug��Ϣ
	*/
	public String getDebugInfo() {
		return debugInfo;
	}
	
	/**
	 * ��ȡ����������URL
	 * @return String
	 * @throws UnsupportedEncodingException 
	 */
	public String getRequestURL() throws UnsupportedEncodingException {
		
		this.createSign();
		
		StringBuffer sb = new StringBuffer();
		Set es = this.parameters.entrySet();
		Iterator it = es.iterator();
		while(it.hasNext()) {
			Map.Entry entry = (Map.Entry)it.next();
			String k = (String)entry.getKey();
			String v = (String)entry.getValue();
			
			if(!"spbill_create_ip".equals(k)) {
				sb.append(k + "=" + URLEncoder.encode(v, WxPayConfig.CHARTSET) + "&");
			} else {
				sb.append(k + "=" + v.replace("\\.", "%2E") + "&");
			}
		}
		
		//ȥ�����һ��&
		String reqPars = sb.substring(0, sb.lastIndexOf("&"));
		
		return this.getGateUrl() + "?" + reqPars;
		
	}
	
	public void doSend() throws UnsupportedEncodingException, IOException {
		this.response.sendRedirect(this.getRequestURL());
	}
	
	/**
	 * ����md5ժҪ,������:���������a-z����,������ֵ�IJ���μ�ǩ��
	 */
	protected void createSign() {
		StringBuffer sb = new StringBuffer();
		Set es = this.parameters.entrySet();
		Iterator it = es.iterator();
		while(it.hasNext()) {
			Map.Entry entry = (Map.Entry)it.next();
			String k = (String)entry.getKey();
			String v = (String)entry.getValue();
			if(null != v && !"".equals(v) 
					&& !"sign".equals(k) && !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + WxPayConfig.KEY);
		
		String sign = MD5Util.MD5Encode(sb.toString(), WxPayConfig.CHARTSET).toUpperCase();
		
		this.setParameter("sign", sign);
		
		//debug��Ϣ
		this.setDebugInfo(sb.toString() + " => sign:" + sign);
		
	}
	
	/**
	*����debug��Ϣ
	*/
	protected void setDebugInfo(String debugInfo) {
		this.debugInfo = debugInfo;
	}
	
	protected HttpServletRequest getHttpServletRequest() {
		return this.request;
	}
	
	protected HttpServletResponse getHttpServletResponse() {
		return this.response;
	}
	
	/**
	 * 自定义函数,官方没有
	 * @param return_code
	 * @param return_msg
	 * @return
	 */
	public static String setXML(String return_code, String return_msg) {
		return "<xml><return_code><![CDATA[" + return_code + "]]></return_code><return_msg><![CDATA[" + return_msg
				+ "]]></return_msg></xml>";
	}
	
	/**
	 * 自定义函数,在官方文档中没有
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public String getRequestXml() throws UnsupportedEncodingException {
		this.createSign();
		
		StringBuffer sb = new StringBuffer();
		sb.append("<xml>");
		Set es = this.parameters.entrySet();
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
				sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
			} else {
				sb.append("<" + k + ">" + v + "</" + k + ">");
			}
		}

		sb.append("</xml>");
		return sb.toString();
	}
}


三、jsp页面代码

3.1 pay.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<%
	String appId = (String)request.getAttribute("appId");
	String timeStamp = (String)request.getAttribute("timeStamp");
	String nonceStr = (String)request.getAttribute("nonceStr");
	String _package = (String)request.getAttribute("package");
	String signType = (String)request.getAttribute("signType");
	String paySign = (String)request.getAttribute("paySign");
%>
<script type="text/javascript">
function callpay()
{
	if (typeof WeixinJSBridge == "undefined") {
	      if (document.addEventListener) {
	        document.addEventListener('WeixinJSBridgeReady', onBridgeReady,
	            false);
	      } else if (document.attachEvent) {
	        document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
	        document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
	      }
	    } else {
	      onBridgeReady();
	    }
}

function onBridgeReady() {
	
	alert("appId=<%=appId %>,timeStamp=<%=timeStamp %>,nonceStr=<%=nonceStr %>,package=<%=_package %>,signType=<%=signType %>,paySign=<%=paySign %>");
	
    WeixinJSBridge.invoke('getBrandWCPayRequest', {
      "appId" : "<%=appId %>",
      "timeStamp" : "<%=timeStamp %>",
      "nonceStr" : "<%=nonceStr %>",
      "package" : "<%=_package %>",
      "signType" : "<%=signType %>",
      "paySign" : "<%=paySign %>"
    }, function(res) { // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回  ok,但并不保证它绝对可靠。  
      //alert(res.err_msg);
      if (res.err_msg == "get_brand_wcpay_request:ok") {
        alert("支付成功");
      }
      if (res.err_msg == "get_brand_wcpay_request:cancel") {
        alert("交易取消");
      }
      if (res.err_msg == "get_brand_wcpay_request:fail") {
        alert("支付失败");
      }
    });
  }
</script>
</head>
<body>
	<div style="text-align: center;margin-top: 50px;"><h1><button type="button" style="display:inline-block;width:600px;height:200px;border-radius:30px;font-size:50px" onclick="callpay()">确认支付</button></h1></div>
</body>
</html>

3.2 notify.jsp

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>恭喜你,支付成功</title>
</head>
<body>
	<div style="text-align:center;">
		<h1>...恭喜你,支付成功...</h1>
		<h3><a href="http://www.appbi.com/wechat/">跳回首页</a></h3>
	</div>
</body>
</html>

好了,至此代码分享完毕,把上述代码复制到工程项目中,只要配置WxPayConfig 这个类的参数即可实现支付功能。

效果如下:

点击pay.jsp页面中的支付按钮弹出支付窗口


此文章本站原创,地址 https://www.vxzsk.com/394.html   转载请注明出处!谢谢!

感觉本站内容不错,读后有收获?小额赞助,鼓励网站分享出更好的教程