微信支付 JAVA实现


微信支付接口文档2.7里的demo实在是看不下去了,错误百出,到网上搜了半天,全部都是把官方文档下下来让你下载,还扣你积分,操蛋。。。

 

微信支付JAVA 接口

首先下载官方demo,虽然很多有问题,但是很多工具类是可以用的

附上地址:https://mp.weixin.qq.com/paymch/readtemplate?t=mp/business/course2_tmpl(别上人家那下还费积分)

1.请求前的拼包

// api支付拼包------------------------------------------------------------------------------	
RequestHandler reqHandler = new RequestHandler(request, response);
// TenpayHttpClient httpClient = new TenpayHttpClient();

// TreeMap<String, String> outParams = new TreeMap<String,String>();
// 初始化
reqHandler.init();
reqHandler.init(APP_ID,APP_SECRET, APP_KEY,PARTNER_KEY);

// 当前时间 yyyyMMddHHmmss
String currTime = TenpayUtil.getCurrTime();
// 8位日期
String strTime = currTime.substring(8, currTime.length());
// 四位随机数
String strRandom = TenpayUtil.buildRandom(4) + "";
// 10位序列号,可以自行调整。
String strReq = strTime + strRandom;
// 订单号,此处用时间加随机数生成,商户根据自己情况调整,只要保持全局唯一就行
String out_trade_no = strReq;

// 设置package订单参数
SortedMap<String, String> packageParams = new TreeMap<String, String>();
packageParams.put("bank_type", "WX"); // 支付类型
packageParams.put("body", "商品名称"); // 商品描述
packageParams.put("fee_type", "1"); // 银行币种
packageParams.put("input_charset", "UTF-8"); // 字符集
packageParams.put("notify_url", "通知地址,接收交易结果,并进行业务处理,例如:http://abc.com/buy/buy.do"); // 通知地址
packageParams.put("out_trade_no", out_trade_no); // 商户订单号
packageParams.put("partner", PARTNER_ID); // 设置商户号
packageParams.put("total_fee", "交易金额"); // 商品总金额,以分为单位
packageParams.put("spbill_create_ip", request.getRemoteAddr()); // 订单生成的机器IP,指用户浏览器端IP

// 获取package包
String packageValue = reqHandler.genPackage(packageParams);
String noncestr = Sha1Util.getNonceStr();
String timestamp = Sha1Util.getTimeStamp();

// 设置支付参数
SortedMap<String, String> signParams = new TreeMap<String, String>();
signParams.put("appid", appid);
signParams.put("noncestr", noncestr);
signParams.put("package", packageValue);
signParams.put("timestamp", timestamp);
signParams.put("appkey", appkey);
// 生成支付签名,要采用URLENCODER的原始值进行SHA1算法!
String sign = Sha1Util.createSHA1Sign(signParams);

// 增加非参与签名的额外参数
signParams.put("paySign", sign);
signParams.put("signType", "SHA1");

// ------------------------------------微信js
// api支付拼包结束------------------------------------

// --------------------------------本地系统生成订单-------------------------------------
//
// --------------------------------生成完成---------------------------------------------

request.setAttribute("appid", appid);
request.setAttribute("timestamp", timestamp);
request.setAttribute("noncestr", noncestr);
request.setAttribute("package", packageValue);
request.setAttribute("paysign", sign);
request.setAttribute("czje", czje);


 英文全大写带下划线的,各位申请微信支付的时候都会给你的。

注意:微信demo里面RequestHandler 在设置商户key和appkey有点问题,ResponseHandler连postData都没获取到,下面把我修正后的贴出来做参考(注:其它java类没什么问题)

 RequestHandler:

package com.zk.common.wxpay;

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.zk.common.wxpay.util.MD5Util;
import com.zk.common.wxpay.util.TenpayUtil;

/*
 '微信支付服务器签名支付请求请求类
 '============================================================================
 'api说明:
 'init(app_id, app_secret, partner_key, app_key);
 '初始化函数,默认给一些参数赋值,如cmdno,date等。
 'setKey(key_)'设置商户密钥
 'getLasterrCode(),获取最后错误号
 'GetToken();获取Token
 'getTokenReal();Token过期后实时获取Token
 'createMd5Sign(signParams);生成Md5签名
 'genPackage(packageParams);获取package包
 'createSHA1Sign(signParams);创建签名SHA1
 'sendPrepay(packageParams);提交预支付
 'getDebugInfo(),获取debug信息
 '============================================================================
 '*/
public class RequestHandler {
	/** Token获取网关地址地址 */
	private String tokenUrl;
	/** 预支付网关url地址 */
	private String gateUrl;
	/** 查询支付通知网关URL */
	private String notifyUrl;
	/** 商户参数 */
	private String appid;
	private String appkey;
	private String partnerkey;
	private String appsecret;
	private String key;
	/** 请求的参数 */
	private SortedMap parameters;
	/** Token */
	private String Token;
	private String charset;
	/** debug信息 */
	private String debugInfo;
	private String last_errcode;

	private HttpServletRequest request;

	private HttpServletResponse response;

	/**
	 * 初始构造函数。
	 * 
	 * @return
	 */
	public RequestHandler(HttpServletRequest request,
			HttpServletResponse response) {
		this.last_errcode = "0";
		this.request = request;
		this.response = response;
		this.charset = "GBK";
		this.parameters = new TreeMap();
		// 验证notify支付订单网关
		notifyUrl = "https://gw.tenpay.com/gateway/simpleverifynotifyid.xml";
		
	}

	/**
	 * 初始化函数。
	 */
	public void init(String app_id, String app_secret, String app_key,
			String partner_key) {
		this.last_errcode = "0";
		this.Token = "token_";
		this.debugInfo = "";
		this.appkey = app_key;
		this.appid = app_id;
		this.partnerkey = partner_key;
		this.key = partner_key;//原demo没有,手动加上
		this.appsecret = app_secret;
	}

	public void init() {
	}

	/**
	 * 获取最后错误号
	 */
	public String getLasterrCode() {
		return last_errcode;
	}

	/**
	 *获取入口地址,不包含参数值
	 */
	public String getGateUrl() {
		return gateUrl;
	}

	/**
	 * 获取参数值
	 * 
	 * @param parameter
	 *            参数名称
	 * @return String
	 */
	public String getParameter(String parameter) {
		String s = (String) this.parameters.get(parameter);
		return (null == s) ? "" : s;
	}

	
	 //设置密钥
	
	public void setKey(String key) {
		this.partnerkey = key;
	}
	//设置微信密钥
	public void  setAppKey(String key){
		this.appkey = key;
	}
	
	// 特殊字符处理
	public String UrlEncode(String src) throws UnsupportedEncodingException {
		return URLEncoder.encode(src, this.charset).replace("+", "%20");
	}

	// 获取package的签名包
	public String genPackage(SortedMap<String, String> packageParams)
			throws UnsupportedEncodingException {
		String sign = createSign(packageParams);

		StringBuffer sb = new StringBuffer();
		Set es = packageParams.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();
			sb.append(k + "=" + UrlEncode(v) + "&");
		}

		// 去掉最后一个&
		String packageValue = sb.append("sign=" + sign).toString();
		System.out.println("packageValue=" + packageValue);
		return packageValue;
	}

	/**
	 * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
	 */
	public String createSign(SortedMap<String, String> packageParams) {
		StringBuffer sb = new StringBuffer();
		Set es = packageParams.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=" + this.getKey());
		System.out.println("md5 sb:" + sb);
		String sign = MD5Util.MD5Encode(sb.toString(), this.charset)
				.toUpperCase();

		return sign;

	}
	/**
	 * 创建package签名
	 */
	public boolean createMd5Sign(String signParams) {
		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 (!"sign".equals(k) && null != v && !"".equals(v)) {
				sb.append(k + "=" + v + "&");
			}
		}

		// 算出摘要
		String enc = TenpayUtil.getCharacterEncoding(this.request,
				this.response);
		String sign = MD5Util.MD5Encode(sb.toString(), enc).toLowerCase();

		String tenpaySign = this.getParameter("sign").toLowerCase();

		// debug信息
		this.setDebugInfo(sb.toString() + " => sign:" + sign + " tenpaySign:"
				+ tenpaySign);

		return tenpaySign.equals(sign);
	}

	

    //输出XML
	   public String parseXML() {
		   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(null != v && !"".equals(v) && !"appkey".equals(k)) {
					
					sb.append("<" + k +">" + getParameter(k) + "</" + k + ">\n");
				}
			}
	       sb.append("</xml>");
			return sb.toString();
		}

	/**
	 * 设置debug信息
	 */
	protected void setDebugInfo(String debugInfo) {
		this.debugInfo = debugInfo;
	}
	public void setPartnerkey(String partnerkey) {
		this.partnerkey = partnerkey;
	}
	public String getDebugInfo() {
		return debugInfo;
	}
	public String getKey() {
		return key;
	}

}

ResponseHandler:

package com.zk.common.wxpay;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import com.zk.common.Parameters;
import com.zk.common.wxpay.util.Sha1Util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jdom.JDOMException;

import com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable;
import com.zk.common.wxpay.util.MD5Util;
import com.zk.common.wxpay.util.TenpayUtil;
import com.zk.common.wxpay.util.XMLUtil;

/**
 * 微信支付服务器签名支付请求应答类 api说明: getKey()/setKey(),获取/设置密钥
 * getParameter()/setParameter(),获取/设置参数值 getAllParameters(),获取所有参数
 * isTenpaySign(),是否财付通签名,true:是 false:否 getDebugInfo(),获取debug信息
 */
public class ResponseHandler {

	private static final String appkey = APP_KEY;
	/** 密钥 */
	private String key;

	/** 应答的参数 */
	private SortedMap parameters;

	/** debug信息 */
	private String debugInfo;

	private HttpServletRequest request;

	private HttpServletResponse response;

	private String uriEncoding;

	private Hashtable xmlMap;
	
	private SortedMap smap;

	public SortedMap getSmap() {
		return smap;
	}

	private String k;

	/**
	 * 构造函数
	 * 
	 * @param request
	 * @param response
	 */
	public ResponseHandler(HttpServletRequest request,
			HttpServletResponse response) {
		this.request = request;
		this.response = response;
		this.smap = new TreeMap<String, String>();
		this.key = "";
		this.parameters = new TreeMap();
		this.debugInfo = "";

		this.uriEncoding = "";
		
		Map m = this.request.getParameterMap();
		Iterator it = m.keySet().iterator();
		while (it.hasNext()) {
			String k = (String) it.next();
			String v = ((String[]) m.get(k))[0];
			this.setParameter(k, v);
		}
		BufferedReader reader  =null;
		try{
			reader = new BufferedReader(new InputStreamReader(request.getInputStream()));    
	        StringBuilder sb = new StringBuilder();    
	        String line = null;    
	        while ((line = reader.readLine()) != null) {    
	            sb.append(line);    
	        }
	        Document doc = DocumentHelper.parseText(sb.toString());
	        Element root = doc.getRootElement(); 
	        for (Iterator iterator = root.elementIterator(); iterator.hasNext();) {
	        	Element e = (Element) iterator.next();  
	        	smap.put(e.getName(), e.getText());
			}

		}catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
        
	}

	/**
	 * 获取密钥
	 */
	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);
	}

	/**
	 * 返回所有的参数
	 * 
	 * @return SortedMap
	 */
	public SortedMap getAllParameters() {
		return this.parameters;
	}

	public void doParse(String xmlContent) throws JDOMException, IOException {
		this.parameters.clear();
		// 解析xml,得到map
		Map m = XMLUtil.doXMLParse(xmlContent);

		// 设置参数
		Iterator it = m.keySet().iterator();
		while (it.hasNext()) {
			String k = (String) it.next();
			String v = (String) m.get(k);
			this.setParameter(k, v);
		}
	}

	/**
	 * 是否财付通签名,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
	 * 
	 * @return boolean
	 */
	public boolean isValidSign() {
		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 (!"sign".equals(k) && null != v && !"".equals(v)) {
				sb.append(k + "=" + v + "&");
			}
		}

		sb.append("key=" + this.getKey());

		// 算出摘要
		String enc = TenpayUtil.getCharacterEncoding(this.request,
				this.response);
		String sign = MD5Util.MD5Encode(sb.toString(), enc).toLowerCase();

		String ValidSign = this.getParameter("sign").toLowerCase();

		// debug信息
		this.setDebugInfo(sb.toString() + " => sign:" + sign + " ValidSign:"
				+ ValidSign);
		System.out.println("财付通签名:"+this.getDebugInfo());

		return ValidSign.equals(sign);
	}

	/**
	 * 判断微信签名
	 */
	public boolean isWXsign() {

		StringBuffer sb = new StringBuffer();
		String keys = "";
		SortedMap<String, String> signParams = new TreeMap<String, String>();
		Set es = this.smap.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 (k != "SignMethod" && k != "AppSignature") {
				signParams.put(k.toLowerCase(), v);
			}
		}
		signParams.put("appkey", this.appkey);
		
		Set set = signParams.entrySet();
		Iterator pit = set.iterator();
		while (pit.hasNext()) {
			Map.Entry entry = (Map.Entry) pit.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			if (sb.length() == 0) {
				sb.append(k + "=" + v);
			} else {
				sb.append("&" + k + "=" + v);
			}
		}

		String sign = Sha1Util.getSha1(sb.toString()).toString().toLowerCase();

		this.setDebugInfo(sb.toString() + " => SHA1 sign:" + sign);
		return sign.equals(this.smap.get("AppSignature"));

	}

	// 判断微信维权签名
	public boolean isWXsignfeedback() {

		StringBuffer sb = new StringBuffer();
		Hashtable signMap = new Hashtable();
		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 (k != "SignMethod" && k != "AppSignature") {

				sb.append(k + "=" + v + "&");
			}
		}
		signMap.put("appkey", this.appkey);

		// ArrayList akeys = new ArrayList();
		// akeys.Sort();
		while (it.hasNext()) {
			String v = k;
			if (sb.length() == 0) {
				sb.append(k + "=" + v);
			} else {
				sb.append("&" + k + "=" + v);
			}
		}

		String sign = Sha1Util.getSha1(sb.toString()).toString().toLowerCase();

		this.setDebugInfo(sb.toString() + " => SHA1 sign:" + sign);

		return sign.equals(this.smap.get("AppSignature"));
	}

	/**
	 * 返回处理结果给财付通服务器。
	 * 
	 * @param msg
	 *            Success or fail
	 * @throws IOException
	 */
	public void sendToCFT(String msg) throws IOException {
		String strHtml = msg;
		PrintWriter out = this.getHttpServletResponse().getWriter();
		out.println(strHtml);
		out.flush();
		out.close();

	}

	/**
	 * 获取uri编码
	 * 
	 * @return String
	 */
	public String getUriEncoding() {
		return uriEncoding;
	}

	/**
	 * 设置uri编码
	 * 
	 * @param uriEncoding
	 * @throws UnsupportedEncodingException
	 */
	public void setUriEncoding(String uriEncoding)
			throws UnsupportedEncodingException {
		if (!"".equals(uriEncoding.trim())) {
			this.uriEncoding = uriEncoding;

			// 编码转换
			String enc = TenpayUtil.getCharacterEncoding(request, response);
			Iterator it = this.parameters.keySet().iterator();
			while (it.hasNext()) {
				String k = (String) it.next();
				String v = this.getParameter(k);
				v = new String(v.getBytes(uriEncoding.trim()), enc);
				this.setParameter(k, v);
			}
		}
	}

	/**
	 * 获取debug信息
	 */
	public String getDebugInfo() {
		return debugInfo;
	}

	/**
	 * 设置debug信息
	 */
	protected void setDebugInfo(String debugInfo) {
		this.debugInfo = debugInfo;
	}

	protected HttpServletRequest getHttpServletRequest() {
		return this.request;
	}

	protected HttpServletResponse getHttpServletResponse() {
		return this.response;
	}

}

2.Jsapi调用

在第一步中已拼好包放入request中了,第二部js调用微信api,看代码:

<script type="text/javascript">
	function callpay(){
	 	WeixinJSBridge.invoke('getBrandWCPayRequest',{
	 		"appId" : "${appid}","timeStamp" : "${timestamp}", "nonceStr" : "${noncestr}", "package" 					: "${package}","signType" : "SHA1", "paySign" : "${paysign}" 
		},function(res){
			WeixinJSBridge.log(res.err_msg);
			if(res.err_msg == "get_brand_wcpay_request:ok"){
				alert("微信支付成功");
			}else if(res.err_msg == "get_brand_wcpay_request:cancel"){
				alert("用户取消支付");
			}else{
				alert("支付失败");
			}
		});
	}
</script>


点击支付按钮,调用callpay 即可。

 

3.微信支付后的通知接口

支付成功了,微信根据你提供的notify_url,来通知你支付成功与否,虽然js里知道了结果,但这里需要正式通知,并处理业务,下面是我的代码片段:

System.out.println("-----------------微信支付来消息啦--------------------------");
ResponseHandler resHandler = new ResponseHandler(request,response);
resHandler.setKey(PARTNER_KEY);

if (resHandler.isValidSign() == true) {
	if (resHandler.isWXsign() == true) {
		// 商户订单号
		String out_trade_no = resHandler
				.getParameter("out_trade_no");
		// 财付通订单号
		String transaction_id = resHandler
				.getParameter("transaction_id");
		// 金额,以分为单位
		String total_fee = resHandler.getParameter("total_fee");
		// 如果有使用折扣券,discount有值,total_fee+discount=原请求的total_fee
		String discount = resHandler.getParameter("discount");
		// 支付结果
		String trade_state = resHandler
				.getParameter("trade_state");
		System.out.println("支付的订单号:" + out_trade_no);
		// 判断签名及结果
		if ("0".equals(trade_state)) {
			System.out.println("哈哈,微信支付成功了");
			// ------------------------------
			// 即时到账处理业务开始
			// ------------------------------
			// 处理数据库逻辑
			// 注意交易单不要重复处理
			// 注意判断返回金额
			// ------------------------------
			// 即时到账处理业务完毕
			// ------------------------------
			System.out.println("success 后台通知成功");
			// 给财付通系统发送成功信息,财付通系统收到此结果后不再进行后续通知
			resHandler.sendToCFT("success");
		} else {// sha1签名失败
			System.out.println("fail -SHA1 failed");
			resHandler.sendToCFT("fail");
		}
	} else {// MD5签名失败
		System.out.println("fail -Md5 failed");
	}
}


到这里OK了,支付接口完成了。

别忘了,还有维权接口,维权接口很简单,接收维权的数据,然后通过api告知微信处理结果就ok了。

看完了记得顶一下哦。。。 

 

猜你喜欢

转载自blog.csdn.net/xiasihua88/article/details/38019847