踩坑微信支付

happybird00 2018-11-26

由于目前电商的用户使用微信访问的居多,所以要在商城集成微信支付,官网Demo仅为工具类及流程,并没有向支付宝那样拿来即用的示例代码,故在这里记录下踩过的坑

1、确保你的微信公众账号已经认证,认证费每年¥300

2、确保已开通微信支付,且已开通微信支付的相应产品,如:扫码支付、H5支付等

3、登录微信支付后台,产品中心>>开发配置>>支付配置,设置相应支付产品的业务域名;获取到后台的下列值

private final String appId  = "";
private final String appSecret = "";
private final String mch_id = "";
private final String key    = "";//32位apiKey

 4、开始踩坑:公众号支付

 4.1:支付页面请求后台获取微信支付初始配置参数

var wxPayConfig;
function getWxPayConfig(cb){ 
	$.ajax({
        type: "GET",
        url: "/xxx/order/wxPayConfig",
        data:{
        	url : encodeURIComponent(window.location.href)
        },
        dataType:"json",
        beforeSend: function () {
            $("#xxx").attr({ "disabled": "disabled" });//获取到配置之前,禁止点击付款按钮
        },
        success: function (data) {
        	wxPayConfig = data;
            $("#xxx").removeAttr("disabled");//获取到配置,打开付款按钮
            wx.config({
                debug: true, // 开启调试模式,成功失败都会有alert框
                appId: data.appId, // 必填,公众号的唯一标识
                timestamp: data.timeStamp, // 必填,生成签名的时间戳
                nonceStr: data.nonceStr, // 必填,生成签名的随机串
                signature: data.signatureShaHex,// 必填,签名
                jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表
            });
            wx.ready(function () {
                // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
            	cb();
            });
            wx.error(function (res) {
                // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
            	//alert(res);
            });
        }
    });
}

先配置参数类:BlsWXPayConfig

public class BlsWXPayConfig extends WXPayConfig {
	private final String appId  = "";
	private final String appSecret = "";
	private final String mch_id = "";
	private final String key    = "";//32位apiKey
    private final String wxPayNotify = "http://www.xxx.com/xxx/wxPayNotify.jsp";//注意不能带参数
    
    public  String getNotifyUrl(){
    	return this.wxPayNotify;
    }
	/* (non-Javadoc)
	 * @see com.wxpay.sdk.WXPayConfig#getAppID()
	 */
	@Override
	public String getAppID() {
		return appId;
	}

	/* (non-Javadoc)
	 * @see com.wxpay.sdk.WXPayConfig#getMchID()
	 */
	@Override
	public String getMchID() {
		return mch_id;
	}

	/* (non-Javadoc)
	 * @see com.wxpay.sdk.WXPayConfig#getKey()
	 */
	@Override
	public String getKey() {
		return key;
	}
	public String getAppSecret() {
		return appSecret;
	}

	/* (non-Javadoc)
	 * @see com.wxpay.sdk.WXPayConfig#getCertStream()
	 */
	@Override
	InputStream getCertStream() {
		return null;
	}

	/* (non-Javadoc)
	 * @see com.wxpay.sdk.WXPayConfig#getWXPayDomain()
	 */
	@Override
	IWXPayDomain getWXPayDomain() {
		return new IWXPayDomain(){

			@Override
			public void report(String domain, long elapsedTimeMillis,
					Exception ex) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public DomainInfo getDomain(WXPayConfig config) {
				return new DomainInfo("www.xxx.com", true);
			}
			
		};
	}

 票据工具类:JsapiTicketUtil

public class JsapiTicketUtil {
	public static final Log LOG = LogFactory.getLog(JsapiTicketUtil.class);
	 
    public static String getJsapiTicket(BlsWXPayConfig wxConfig) {
        String requestUrl = "https://api.weixin.qq.com/cgi-bin/token?";
        String params = "grant_type=client_credential&appid=" + wxConfig.getAppID() + "&secret=" + wxConfig.getAppSecret() + "";
        String result = httpGet(requestUrl + params);
        String access_token = JsonUtils.fromJson(result, WxAuthPros.class).getAccess_token();
        requestUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?";
        params = "access_token=" + access_token + "&type=jsapi";
        result = httpGet(requestUrl + params);
        String jsapi_ticket = JsonUtils.fromJson(result, WxAuthPros.class).getTicket();
        return jsapi_ticket;
    }
 
    /**
     * post请求
     * @param url
     * @return
     */
    public static String httpPost(String url) {
        //post请求返回结果
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost method = new HttpPost(url);
        String str = "";
        try {
            HttpResponse result = httpClient.execute(method);
            url = URLDecoder.decode(url, "UTF-8");
            /**请求发送成功,并得到响应**/
            if (result.getStatusLine().getStatusCode() == 200) {
                try {
                    /**读取服务器返回过来的json字符串数据**/
                    str = EntityUtils.toString(result.getEntity());
                } catch (Exception e) {
                    LOG.error("post请求提交失败:" + url, e);
                }
            }
        } catch (IOException e) {
            LOG.error("post请求提交失败:" + url, e);
        }
        return str;
    }
 
    /**
     * get 请求、
     * @param url
     * @return
     */
    public static String httpGet(String url) {
        //get请求返回结果
        String strResult = null;
        try {
            DefaultHttpClient client = new DefaultHttpClient();
            //发送get请求
            HttpGet request = new HttpGet(url);
            HttpResponse response = client.execute(request);
 
            /**请求发送成功,并得到响应**/
            if (response.getStatusLine().getStatusCode() == org.apache.http.HttpStatus.SC_OK) {
                /**读取服务器返回过来的json字符串数据**/
                strResult = EntityUtils.toString(response.getEntity());
            } else {
                LOG.error("get请求提交失败:" + url);
            }
        } catch (IOException e) {
            LOG.error("get请求提交失败:" + url, e);
        }
        return strResult;
    }

 对应后台代码:

/**
	 * 获取微信初始化配置
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return
	 */
	public ActionForward wxPayConfig(ActionMapping mapping, ActionForm form, 
			HttpServletRequest request, HttpServletResponse response){
		 long timeStamp   = WXPayUtil.getCurrentTimestamp();
         String nonceStr  = WXPayUtil.generateNonceStr();

         Map<String, String> data = new TreeMap<String, String>();
         BlsWXPayConfig wxConfig = new BlsWXPayConfig();
		try {
			String url = URLDecoder.decode(request.getParameter("url").split("#")[0], "UTF-8");
	        String jsapi_ticket = JsapiTicketUtil.getJsapiTicket(wxConfig);
	        data.put("jsapi_ticket", jsapi_ticket);
	        data.put("noncestr", nonceStr);
	        data.put("timestamp", String.valueOf(timeStamp));
	        data.put("url", url);
	        String string1 = "jsapi_ticket=" + jsapi_ticket +
	                "&noncestr=" + nonceStr +
	                "&timestamp=" + timeStamp +
	                "&url=" + url;
	        
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(string1.getBytes("UTF-8"));

			String signatureMd5 = WXPayUtil.generateSignature(data, wxConfig.getKey());
			String signatureShaHex = DigestUtils.shaHex(string1);;
            
			JSONObject jsonData = new JSONObject();
			jsonData.put("jsapi_ticket", jsapi_ticket);
			jsonData.put("url", url);
			
			jsonData.put("appId", wxConfig.getAppID());
			jsonData.put("timeStamp", timeStamp);
			jsonData.put("nonceStr" , nonceStr);
			jsonData.put("signatureMd5", signatureMd5);
			jsonData.put("signatureShaHex", signatureShaHex);
			super.responseWrite(response, jsonData);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

 4.2 点击按钮唤起微信支付,调用前需要先获得Code

function getQueryString(name){
     var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
     var r = window.location.search.substr(1).match(reg);
     if(r!=null)return  unescape(r[2]); return null;
} 
var code = getQueryString("code");
if(code != "" && code != "null"){//授权后直接唤起支付
	   startWxPay();
}
function startWxPay() {
	if(!wxPayConfig){
		return getWxPayConfig(startWxPay)
	}
    var code =  getQueryString("code");
    if(code == "" || code == "null"){
    	var url = window.location.href;
    	return window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + wxPayConfig.appId +
    			"&redirect_uri=" + encodeURIComponent(url)
    			"&response_type=code" +
    			"&scope=snsapi_base" +
    			"&state=123" +
    			"#wechat_redirect";
    } 
    $.ajax({ 
        type: "POST",
        url: "/xxx/order/getWxPaySign",
        data: { 
        	"code": code,
        	"orderId" : $("#ordId").val(),
        	"orderNumber" : $("#orderNumber").val(),
        	"total_fee" : $("#ototalPrice").val()
        },
        dataType:"json",
        beforeSend: function () {
            $("#xxx").attr({ "disabled": "disabled" });
        },
        success: function (res) {
            $("#xxx").removeAttr("disabled");
            if (res.openid != null && res.openid != undefined && res.openid != "") {
                window.localStorage.setItem("openid", res.openid);
            }
            wx.chooseWXPay({
                timestamp: res.timeStamp, // 支付签名时间戳
                nonceStr: res.nonceStr, // 支付签名随机串,不长于32 位
                "package": res["package"], // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
                signType: res.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
                paySign: res.paysign, // 支付签名
                success: function (res) {
                    //支付成功
                	window.location.href = "/xxx/order/detail?id=" + $("#ordId").val();
                },
                cancel: function (res) {
                    //支付取消
                }
            });
        }
    });
    var isPageHide = false;
    window.addEventListener('pageshow', function() {
        if(isPageHide) {
            window.location.reload();//自己重新刷新,这一步相当于模拟了跳转
        }
    });
    window.addEventListener('pagehide', function() {
        isPageHide = true;
    });
}

 对应后台代码:

public String getIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
    }
/**
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return
	 */
	public ActionForward getWxPaySign(ActionMapping mapping, ActionForm form, 
			HttpServletRequest request, HttpServletResponse response){
		String code    = request.getParameter("code") ;

        BlsWXPayConfig wxPayConfig =  new BlsWXPayConfig();
        String key    = wxPayConfig.getKey();//32位apiKey
        
        String nonceStr  = WXPayUtil.generateNonceStr();
        String notify_url = wxPayConfig.getNotifyUrl();//支付结果回调地址,不能带参数(PayNotifyUrl回调里能接到订单号out_trade_no参数)
        String out_trade_no = request.getParameter("orderNumber");//订单号
        String spbill_create_ip = getIp(request);//用户端IP
        String trade_type = "JSAPI";//JSAPI,NATIVE,APP,WAP

        //#region 获取用户微信OpenId
        String openidExt = null;
		try {
			Map<String, String> reqData = new TreeMap<String, String>();
        	openidExt = PayCommonUtil.getOpenId(code, wxPayConfig);
	        //#region 调用统一支付接口获得prepay_id(预支付交易会话标识)
	        reqData.put("appid", wxPayConfig.getAppID());
	        reqData.put("mch_id", wxPayConfig.getMchID());
	        reqData.put("nonce_str", nonceStr);
	        reqData.put("body", out_trade_no);// + " 购货金额");
	        reqData.put("out_trade_no", out_trade_no);
	        
	        String total_fee = request.getParameter("total_fee");
	        int total_fee_int = new BigDecimal(Double.parseDouble(total_fee) * 100).setScale(2, RoundingMode.HALF_UP).intValue();// 
	        
	        reqData.put("total_fee", String.valueOf(total_fee_int));//单位为分
	        reqData.put("spbill_create_ip", spbill_create_ip);
	        reqData.put("notify_url", notify_url);
	        reqData.put("trade_type", trade_type);
	        
	        String attach = request.getParameter("orderId");//附加数据:订单id
	        reqData.put("attach", attach);
	         
	        reqData.put("openid", openidExt);
	        String sign = WXPayUtil.generateSignature(reqData, key);
	        reqData.put("sign", sign);

	        
	         WxAuthPros wxAuth = PayCommonUtil.unifiedorder(PayCommonUtil.getxml(reqData));
	         String prepay_id = wxAuth.getPrepay_id();
	        //#endregion
	
	         long timestamp = WXPayUtil.getCurrentTimestamp();
	        
	        Map<String, String> paySignMap = new TreeMap<String, String>();
	        paySignMap.put("appId", wxPayConfig.getAppID());
	        paySignMap.put("nonceStr", nonceStr);
	        paySignMap.put("package", "prepay_id=" + prepay_id);
	        paySignMap.put("signType", "MD5");
	        paySignMap.put("timeStamp", String.valueOf(timestamp));
	        String paySign = WXPayUtil.generateSignature(paySignMap, key);

	        JSONObject resData = new JSONObject();
	        resData.put("openid", openidExt);
	        resData.put("appId", wxPayConfig.getAppID());
	        resData.put("timeStamp", WXPayUtil.getCurrentTimestamp());
	        resData.put("nonceStr", nonceStr);
	        resData.put("package", "prepay_id=" + prepay_id);
	        resData.put("signType", "MD5");
	        
	        resData.put("sign", sign);
	        resData.put("paysign", paySign);
	        resData.put("openid", openidExt);
	        resData.put("result_code", wxAuth.getResult_code());
	        resData.put("return_msg", wxAuth.getReturn_msg());
	        //#endregion
	
	        super.responseWrite(response, resData.toString());
		} catch (Exception e) {
			LOG.error("获取微信支付签名异常", e);
		}
		return null;
    }

 工具类:PayCommonUtil

public class PayCommonUtil {
	private static String OPENIDURL = "https://api.weixin.qq.com/sns/oauth2/access_token?"; // 获取微信openid的链接
	private static String UNURL = "https://api.mch.weixin.qq.com/pay/unifiedorder"; // 微信统一下单链接
/**
	 * ** 接收微信的异步通知
	 * 
	 * @throws IOException
	 */
	public static String reciverWx(HttpServletRequest request)
			throws IOException {
		InputStream inputStream;
		StringBuffer sb = new StringBuffer();
		inputStream = request.getInputStream();
		String s;
		BufferedReader in = new BufferedReader(new InputStreamReader(
				inputStream, "UTF-8"));
		while ((s = in.readLine()) != null) {
			sb.append(s);
		}
		in.close();
		inputStream.close();
		return sb.toString();
	}
	/**
	 * 获取openId
	 * @param code
	 * @param config
	 * @return
	 */
	public static String getOpenId(String code, BlsWXPayConfig config) {
		String openIdUrl = OPENIDURL + "appid=" + config.getAppID()
				+ "&secret=" + config.getAppSecret() + "&code=" + code
				+ "&grant_type=authorization_code";
		try {
			HttpRequest request = HttpRequest.post(openIdUrl).contentType(
					"application/json;charset=utf-8");
			String res = request.body();
			if (res != null) {
				WxAuthPros wxAuth = JsonUtils.fromJson(res, WxAuthPros.class);
				return wxAuth.getOpenid();

			}
			return null;
		} catch (Exception e) {
			return null;
		}
	}
	//组装统一下订单参数并进行签名

    public static String getxml(Map<String, String> reqData){
    	StringBuilder returnXml = new StringBuilder();
        try {
	       returnXml.append("<xml>");
		       returnXml.append("<appid>").append(reqData.get("appid")).append("</appid>");
			   returnXml.append("<mch_id>").append( reqData.get("mch_id")).append("</mch_id>");
			   returnXml.append("<nonce_str>").append(reqData.get("nonce_str")).append("</nonce_str>");
			   returnXml.append("<body>").append(reqData.get("body")).append("</body>");
			   returnXml.append("<out_trade_no>").append(reqData.get("out_trade_no")).append("</out_trade_no>");
			   returnXml.append("<total_fee>").append(reqData.get("total_fee")).append("</total_fee>");
			   returnXml.append("<spbill_create_ip>").append(reqData.get("spbill_create_ip")).append("</spbill_create_ip>");
			   returnXml.append("<notify_url>").append(reqData.get("notify_url")).append("</notify_url>");
			   returnXml.append("<trade_type>").append(reqData.get("trade_type")).append("</trade_type>" );
			   if(reqData.containsKey("product_id")){
				   returnXml.append("<product_id>").append(reqData.get("product_id")).append("</product_id>" );
			   }
			   returnXml.append("<attach>").append(reqData.get("attach")).append("</attach>");
			   if(reqData.containsKey("openid")){
				   returnXml.append("<openid>").append(reqData.get("openid")).append("</openid>");
			   }
			   returnXml.append("<sign>").append(reqData.get("sign")).append("</sign>");
		   returnXml.append("</xml>");
		} catch (Exception e) { 
		}
	    return returnXml.toString(); 
	
	}
	// 调用微信统一下单接口
	public static WxAuthPros unifiedorder(String xml){
		String returnxml=null;
		WxAuthPros wxAuth = new WxAuthPros();
		try {
			HttpRequest request = HttpRequest.post(UNURL).contentType( "application/json;charset=utf-8").send(xml);
			returnxml = request.body();
			
//			System.out.println("-------------------------------------------");
//			System.out.println(xml);
//			System.out.println("++++++++++++++++++++++++++++++++++++++++++++");
//			System.out.println(returnxml);
//			System.out.println("-------------------------------------------");
			
			Document doc = DocumentHelper.parseText(returnxml);
			Element rootElt = doc.getRootElement(); // 获取根节点
			wxAuth.setPrepay_id(rootElt.elementText("prepay_id"));
			wxAuth.setResult_code(rootElt.elementText("result_code"));
			wxAuth.setErr_code(rootElt.elementText("err_code"));
			wxAuth.setErr_code(rootElt.elementText("err_code"));
			wxAuth.setErr_code_des(rootElt.elementText("err_code_des"));
			wxAuth.setReturn_msg(rootElt.elementText("return_msg"));
			wxAuth.setCode_url(rootElt.elementText("code_url"));
			wxAuth.setMweb_url(rootElt.elementText("mweb_url"));
		} catch (Exception e) { 
		}
		return wxAuth;
	}

   /** 获取二维码url  
	 * @param ip
	 * @param vcWeixinPay
	 * @return
	 * @throws Exception
	 */
   private static WxAuthPros weixin_pay(String ip, 
		   String attach, String out_trade_no, Double totalPrice, 
		   BlsWXPayConfig wxPayConfig, 
		   String trade_type) throws Exception {  
	   String key = wxPayConfig.getKey(); // key  
	   String nonce_str = WXPayUtil.generateNonceStr();
	   // 获取发起电脑 ip  
	   String spbill_create_ip = ip;  
	   
	   
	   Map<String, String> reqData = new TreeMap<String, String>();
	   //#endregion
	   //#region 调用统一支付接口获得prepay_id(预支付交易会话标识)
	   reqData.put("appid", wxPayConfig.getAppID());
	   reqData.put("mch_id", wxPayConfig.getMchID());
	   reqData.put("nonce_str", nonce_str);
	   reqData.put("body", out_trade_no);// + " 购货金额");
	   reqData.put("out_trade_no", out_trade_no);
	   
	   int total_fee_int = new BigDecimal(totalPrice * 100).setScale(2, RoundingMode.HALF_UP).intValue();// 
	   
	   reqData.put("total_fee", String.valueOf(total_fee_int));//单位为分
	   reqData.put("spbill_create_ip", spbill_create_ip);
	   reqData.put("notify_url", wxPayConfig.getNotifyUrl());
	   reqData.put("trade_type", trade_type);
	   reqData.put("product_id", attach);//trade_type = NATIVE 时,必填
	   reqData.put("attach", attach);
	   
	   String sign = WXPayUtil.generateSignature(reqData, key);
	   reqData.put("sign", sign);
	   
	   WxAuthPros wxAuth = PayCommonUtil.unifiedorder(PayCommonUtil.getxml(reqData));
	   return wxAuth;   
   }
   /** 网页二维码扫码支付
	 * @param ip
	 * @param attach
	 * @param out_trade_no
	 * @param totalPrice
	 * @param wxPayConfig
	 * @return
	 * @throws Exception
	 */
	public static WxAuthPros weixin_payByQrcode(String ip, 
		   String attach, String out_trade_no, Double totalPrice, 
		   BlsWXPayConfig wxPayConfig) throws Exception { 
	   return weixin_pay(ip, attach, out_trade_no, totalPrice, wxPayConfig, "NATIVE");
   }
	/** 网页二维码扫码支付
	 * @param ip
	 * @param attach
	 * @param out_trade_no
	 * @param totalPrice
	 * @param wxPayConfig
	 * @return
	 * @throws Exception
	 */
	public static WxAuthPros weixin_payByH5(String ip, 
			String attach, String out_trade_no, Double totalPrice, 
			BlsWXPayConfig wxPayConfig) throws Exception { 
		return weixin_pay(ip, attach, out_trade_no, totalPrice, wxPayConfig, "MWEB");
	}

5、扫码支付:用户点击按钮提交参数到后台,后台调用微信支付生成二维码链接内容,前台显示二维码,用户扫码支付,前台轮训后台是否支付成功。

后台代码:

/**
	 * 订单列表点击 微信支付
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return
	 */
	public ActionForward wxpay(ActionMapping mapping, ActionForm form, 
			HttpServletRequest request, HttpServletResponse response){
		String ip = super.getIp(request);
		BlsWXPayConfig wxPayConfig = new BlsWXPayConfig();
		WxAuthPros wxAuthPros;
		try {
			wxAuthPros = PayCommonUtil.weixin_payByQrcode(
					ip == null ? "" : ip.toString(), 
					request.getParameter("orderId"),
					request.getParameter("orderNumber"),
					Double.parseDouble(request.getParameter("tenantOrderFee")),
					wxPayConfig);
			request.setAttribute("wxAuthPros", wxAuthPros);
			request.setAttribute("orderId", request.getParameter("ordId"));
			request.getRequestDispatcher("order/weixinPay.jsp").forward(
							request, response);
		} catch (Exception e) {
			LOG.error("调用微信支付 异常", e);;
		}
		return null;
	}
jsp 代码,显示二维码
<%
	    	com.wxpay.sdk.WxAuthPros wxAuthPros = (com.wxpay.sdk.WxAuthPros)request.getAttribute("wxAuthPros");
	    	%>
	    	<div style="padding: 30px;text-align: center;">
		         <div id="qrcode" urlText="<%=wxAuthPros.getCode_url() %>" 
		         	orderId="<%=request.getAttribute("orderId") %>"
		         	errorMsg="<%=wxAuthPros.getReturn_msg() %>">
		         	
		         </div>
		         <div style="line-height: 30px;font-size: 16px;">
		         		请使用微信扫码,完成支付。
		         </div>
		     </div>
 Js代码, 显示二维码使用jquery.qrcode方式
$(function(){ 
	var urlText = $('#qrcode').attr("urlText");
	$('#qrcode').qrcode({
	    render: "canvas", //也可以替换为table
	    width: 200,
	    height: 200,
	    text: urlText
	});
	if(urlText != "null"){
		setInterval(function(){
			$.ajax({
				url : "/xxx/vlidateWxPay",
				data : {
					orderId : $('#qrcode').attr("orderId")
				},
				success: function(res){
					if(res == "true"){
						alert("恭喜,支付成功!点击确定跳转至“我的订单”页面");
						//支付成功 跳转到我的订单页面
						window.location.href = "/xxx/order.html";
					}
				}
			});
		}, 1000);
	}
});
 6、H5支付,用户点击按钮触发支付,请求后台得到微信统一下单H5支付链接,前台跳转到微信支付链接,支付成功,微信请求回调页面(如果为app端唤起微信支付,返回后需轮询后台验证是否支付成功)

JS代码:

/**
 * 微信外浏览器唤起微信支付
 * */
function startWxH5Pay(){
	$.ajax({ 
        type: "POST",
        url: "/xxx/order/getWxH5Url",
        data: { 
        	"orderId" : $("#ordId").val(),
        	"orderNumber" : $("#orderNumber").val(),
        	"total_fee" : $("#ototalPrice").val()
        },
        dataType:"json",
        beforeSend: function () {
            $("#xxx").attr({ "disabled": "disabled" });
        },
        success: function (res) {
        	if(res && res.mweb_url){
        		//弹出提示框
	            mui("#payModal").popover("show", this);
				$("#payCancel").on("click", function(){
		            mui("#payModal").popover("hide", this);
				});
				$("#payComplate").on("click", function(){
		            mui("#payModal").popover("hide", this);
		    		setInterval(function(){
		    			$.ajax({
		    				url : "/xxx/order/vlidateWxPay",
		    				data : {
		    					orderId : $("#ordId").val()
		    				},
		    				success: function(res){
		    					if(res == "true"){
		    						alert("恭喜,支付成功!点击确定跳转至“我的订单”页面");
		    						//支付成功 跳转到我的订单页面
		    						window.location.href = "/xxx/order.html";
		    					}
		    				}
		    			});
		    		}, 1000);
		    	
				});
        		window.location.href = res.mweb_url;
        	}
    	}
    });
}
 对应后台代码:
/**
	 * 手机端:微信外浏览器h5支付
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return
	 */
	public ActionForward getWxH5Url(ActionMapping mapping, ActionForm form, 
			HttpServletRequest request, HttpServletResponse response){
		String ip = super.getIp(request);
		BlsWXPayConfig wxPayConfig = new BlsWXPayConfig();
		WxAuthPros wxAuthPros;
		try {
			wxAuthPros = PayCommonUtil.weixin_payByH5(
							ip == null ? "" : ip.toString(), 
							request.getParameter("orderId"),
							request.getParameter("orderNumber"),
							Double.parseDouble(request.getParameter("total_fee")),
							wxPayConfig);
			super.responseWrite(response, new JSONObject(wxAuthPros));
		} catch (Exception e) {
			LOG.error("调用微信支付 异常", e);;
		}
		return null;
	}
 

 以上为微信支付的几种代码调用方式,回调代码如下(由于回调不能写参数,所有暂时使用的jsp代码)

<!-- 该引入的要引入 -->
 <%@page import="java.io.PrintWriter"%>
 <%@page import="org.springframework.web.context.WebApplicationContext" %>
 <%@page import="org.springframework.web.context.support.WebApplicationContextUtils" %>
 <%@page import="com.xxx.moder.BlsWxPayInfo" %>
 <%@page import="com.wxpay.sdk.WXPayUtil" %>
 <%@page import="com.wxpay.sdk.PayCommonUtil" %>
 <%@page import="java.util.Map" %>
 <%@page import="java.util.List" %>
 <%@page import="java.util.HashMap" %>
 <%@page import="java.util.TreeMap" %>
 <%@page import="java.util.SortedMap" %>
 <%@page import="java.util.Iterator" %>
 <%@page import="java.io.BufferedOutputStream" %>
 <%@page import="org.dom4j.DocumentHelper" %>
 <%@page import="org.dom4j.Document" %>
 <%@page import="org.dom4j.Element" %>
 <% 
   	WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
	com.xxx.service.OrderService orderService = (com.xxx.service.OrderService) ctx.getBean("OrderService");
	 
	//orderService.
	
	String result = PayCommonUtil.reciverWx(request); // 接收到异步的参数
    Map<String, String> m = new TreeMap<String, String>();// 解析xml成map
    if (result != null && !"".equals(result))  {
	   	try {
			Document doc = DocumentHelper.parseText(result);
			Element rootElt = doc.getRootElement(); // 获取根节点
			List<Element> child = rootElt.elements();
			for(Element e : child){
				m.put(e.getName(), e.getText());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
    }  
    // 判断签名是否正确
    String resXml = "";
    if(WXPayUtil.isSignatureValid(m, "Blissunnnnnnnnnnnnnnnnnnnnnnnnnn")){
        if ("SUCCESS".equals((String) m.get("result_code")))  {
            // 如果返回成功
            String mch_id = (String) m.get("mch_id"); // 商户号
            String out_trade_no = (String) m.get("out_trade_no"); // 商户订单号
            String total_fee = (String) m.get("total_fee");
            String transaction_id = (String) m.get("transaction_id"); // 微信支付订单号
            String attach = (String) m.get("attach"); // 微信支付订单号
            
            BlsWxPayInfo blsWxPayInfo = new BlsWxPayInfo();
            blsWxPayInfo.setMch_id(mch_id);
            blsWxPayInfo.setOut_trade_no(out_trade_no);
            blsWxPayInfo.setTotal_fee(Double.parseDouble(total_fee));
            blsWxPayInfo.setTransaction_id(transaction_id);
            blsWxPayInfo.setDevice_info((String)m.get("device_info"));
            blsWxPayInfo.setNonce_str((String)m.get("nonce_str"));
            blsWxPayInfo.setSign((String)m.get("sign"));
            blsWxPayInfo.setResult_code((String)m.get("result_code"));
            blsWxPayInfo.setTrade_type((String)m.get("trade_type"));
            blsWxPayInfo.setAttach((String)m.get("attach"));
            orderService.saveBlsWxPayInfo(blsWxPayInfo);
            
            
	        resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
	                  + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
        } else {// 如果微信返回支付失败,将错误信息返回给微信
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[交易失败]]></return_msg>" + "</xml> ";
        }
    } else {
        resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                + "<return_msg><![CDATA[通知签名验证失败]]></return_msg>" + "</xml> ";
    }

    // 处理业务完毕,将业务结果通知给微信
    // ------------------------------
    try{
	    BufferedOutputStream outStream = new BufferedOutputStream(response.getOutputStream());
	    outStream.write(resXml.getBytes());
	    outStream.flush();
    	outStream.close();
    }catch(Exception e){
    	
    }
%>

 至此已完成微信支付的几种代码的编写,开始的时候老是提示签名错误,微信签名一定要注意参数的名称及顺序(为了保证顺序请使用TreeMap),还有公众号支付时需要二次签名,签名的 参数值不能为空,trade_type=NATIVE时product_id必填,trade_type=JSAPI时openid必填。

相关推荐