java微信支付,微信公众号支付jsapi版(转)

2017年08月07日 21:38 | 5043次浏览 作者原创 版权保护

微信支付官方文档给的太乱并且还居然有好多错误,导致好多初学者走了好多弯路,甚至摸不着头脑。这节给大家介绍代码+解说并附有源码(文章底部有下载按钮)。

目前微信支付最新版本为V3版本,官方并且有几种语言版本,其中就有java版本,下载地址为:

https://mp.weixin.qq.com/paymch/readtemplate?t=mp/business/course2_tmpl

微信支付成功后  你的邮件会有以下信息:

1、 信息包括:商户ID(mch_id)、申请编号、登录帐号、登录密码、商户API密码(key)

2.、证书包括:商户API证书、证书密钥、CA证书

开发前,我们先登录自己的服务号,点击微信支付----->开发配置。

如果这里的授权路径和下面参数的notify_url不对  调用付款接口时会弹出access_denied。

比如,我的授权目录是http://183.33.212.175/wxweb/config/,那么我对应的notify_url的回调方法必须是String notify_url = "http://183.33.212.175:8016/wxweb/config/pay!paySuccess.action";这样的

二,代码示例

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");  
    }  
}

到了这里,支付的整个流程就结束了,如果读者按照步骤来,是可以能成功做出微信公众号支付的。


小说《我是全球混乱的源头》
此文章本站原创,地址 https://www.vxzsk.com/85.html   转载请注明出处!谢谢!

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