JSAPI公众号支付流程

1. JSAPI支付申请和配置

申请商户号和公众号 ,获取四大支付要素: merchant_id、key、appid、appSecret

公众号: appid和appSecret以及配置授权回调地址(否则会报:redirect_uri与后台配置不一致的错误)
在这里插入图片描述

在这里插入图片描述
商户号:mch_id和key以及授权目录(否则再拉起支付的时候报当前URL未注册)
在这里插入图片描述

在这里插入图片描述

2. 支付流程梳理

  • 根据appid获取code

(1)地址以及示例:https://open.weixin.qq.com/connect/oauth2/authorize?appid=1111&redirect_uri=22222&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect

(2)跳转授权地址redirect_uri后(一般是一个方法的地址),就能获取到code
String code = request.getParameter(“code”);

//授权回调获取code
1----public String getAuthorizeInfo(String authorizeInfo) throws UnsupportedEncodingException {
        String redirectUri = wechatConfig.getWechatRedirectUri();
        logger.info("微信授权地址为:" + redirectUri);
        logger.info("------authorizeInfo:" + authorizeInfo);
        //如果参数不为空,拼接参数
        if (StringUtils.isNotEmpty(authorizeInfo)) {
            authorizeInfo += "&payNotify=" + wechatConfig.getPayNotify() + "&cancelNotify=" + wechatConfig.getCancelNotify() + "&findNotifyUrl="
                    + wechatConfig.getFindNotifyUrl();
            redirectUri = redirectUri + "?" + authorizeInfo;
        } else {
            authorizeInfo += "payNotify=" + wechatConfig.getPayNotify() + "&cancelNotify=" + wechatConfig.getCancelNotify() + "&findNotifyUrl="
                    + wechatConfig.getFindNotifyUrl();
            redirectUri = redirectUri + "?" + authorizeInfo;
        }
        logger.info("-----微信授权地址2为:" + redirectUri);
        //地址进行encode处理
        redirectUri = URLEncoder.encode(redirectUri, "utf-8");
        //封装授权地址
        StringBuffer sb = new StringBuffer();
        sb.append(WechatPaymentConstants.AUTHORIZE_URL);
        sb.append("?appid=").append(wechatConfig.getWechatAppid());
        sb.append("&redirect_uri=").append(redirectUri);
        sb.append("&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect");
        return sb.toString();
        
 2---- response.sendRedirect(sb.toString());
    }

  • 根据code获取openid

(1)地址以及示例:https://api.weixin.qq.com/sns/oauth2/access_token?appid=wxfb5b168fe46a40d8&secret=17ce5aa1ded73c1dc5b8d3f702191180&code=021dQUqz0RD7ie1YwGsz0HzTqz0dQUqh&grant_type=authorization_code
(2) 返回参数格式:{“access_token”:“17_1PPobPecvywAZqmYJKMBghfH9kjqimxt7kveqPtVMhH3ydC_jNsGuG6atRaY9gWZNzfDFs68lfhbiTbw7kiW_3iDaZDMqHCFXy5pmAf-KBc”,“expires_in”:7200,“refresh_token”:“17_EqKT6GrLU6bX0j9sre1EI9MXU5Lsnsl-nvPwHW0WrizvlHSWhhNE9LC2Qq0j-wwiZ9EyjyDSeNCeT8tagwAYqjNvHdKajK7fcC_M1JjvYOo”,“openid”:“oak-OvzNbhO7J6v7dKpX4gpJUGes”,“scope”:“snsapi_base”}

public String getOpenidByCode(String code) throws Exception {
        //封装请请求地址
        StringBuffer sb = new StringBuffer();
        sb.append(WechatPaymentConstants.TOKEN_URL);
        sb.append("?appid=").append(wechatConfig.getWechatAppid());
        sb.append("&secret=").append(wechatConfig.getWechatAppSecret());
        sb.append("&code=").append(code);
        sb.append("&grant_type=authorization_code");
        logger.info("获取openid请求地址:" + sb.toString());
        // 定义日志对象
        //RequestInfoDTO tReportLogDTO = new RequestInfoDTO();
        String accessInfo = HttpClientUtil.originalGetData(sb.toString());
        logger.info("getOpenidByCode请求:" + accessInfo);
        return accessInfo;
    }
  • 调用统一下单接口

https://api.mch.weixin.qq.com/pay/unifiedorder

(1).准备统一下单报文:
示例:<xml>
  <appid>wx7ad792621769e980</appid>
  <mch_id>1449823102</mch_id>
  <device_info>WEB</device_info>
  <nonce_str>PlTZGZL60eMed8ZAlocJfes1XsQeDNmD</nonce_str>
  <sign>E4E92C23296BE4B84541E92F4039DF6B</sign>
  <body>1分钱测试方案</body>
  <out_trade_no>P00000326611</out_trade_no>
  <fee_type>CNY</fee_type>
  <total_fee>1</total_fee>
  <spbill_create_ip>192.168.122.1</spbill_create_ip>
  <notify_url>http://weixindev.fosun-uhi.com/sinopay-web-weixinpay/sinopay/wechatNotify/wechatNotify.do</notify_url>
  <trade_type>JSAPI</trade_type>
  <openid>oak-OvzNbhO7J6v7dKpX4gpJUGes</openid>
  <limit_pay>no_credit</limit_pay>
</xml>

(2).下单返回报文:
<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg><appid><![CDATA[wx7ad792621769e980]]></appid><mch_id><![CDATA[1449823102]]></mch_id><device_info><![CDATA[WEB]]></device_info><nonce_str><![CDATA[kGBKwYesPbc1h73z]]></nonce_str><sign><![CDATA[882C7F27DAFD5341CF9A8848513CEC54]]></sign><result_code><![CDATA[SUCCESS]]></result_code><prepay_id><![CDATA[wx272122146318383044375e1f3027269817]]></prepay_id><trade_type><![CDATA[JSAPI]]></trade_type></xml>

(3).根据返回的参数,组装拉起支付的参数
其中参数有签名参数,是对这几个字段签名:appId、nonceStr 随机字符串(RandomStringUtil.getRandomString32())、package(值为 prepay_id)、signType、timeStamp

(4).准备参数-签名:
WechatSignUtil.getSign();
getSign获取签名,加入到请求支付请求报文中
用WXPayUtil中的publicstatic String generateSignature(final Map<String, String> data, Stringkey)方法,key是
&nonceStr="", 这样的格式拼接参数
public WechatPaymentResultDTO wechatPrePayment(String payNo, String openid) throws SinoBaseCheckException, Exception {
        // TODO Auto-generated method stub
        logger.info("统一下单支付开始......");
        PaymentInfoDetailDTO wPaymentInfoDetailDTO = getPaymentTradeForPayNo(payNo);
        //准备统一下单参数
        WechatPrePaymentRequestDTO wWechatPrePaymentRequestDTO = new WechatPrePaymentRequestDTO();
        wWechatPrePaymentRequestDTO.setAppid(wechatConfig.getWechatAppid());//公众账号ID
        wWechatPrePaymentRequestDTO.setMch_id(wechatConfig.getWechatMchid());//商户号
        wWechatPrePaymentRequestDTO.setDevice_info("WEB");//设备号
        wWechatPrePaymentRequestDTO.setNonce_str(RandomStringUtil.getRandomString32());//随机字符串
        wWechatPrePaymentRequestDTO.setBody(wPaymentInfoDetailDTO.getTradeDesc());//商品描述
        wWechatPrePaymentRequestDTO.setOut_trade_no(payNo);//商户订单号
        wWechatPrePaymentRequestDTO.setFee_type("CNY");//货币类型
        wWechatPrePaymentRequestDTO.setLimit_pay("no_credit");//限制信用卡支付
        /*if (isLimitPay(wPaymentInfoDetailDTO)) {
            wWechatPrePaymentRequestDTO.setLimit_pay("no_credit");//限制信用卡支付
        }*/
        String tPayAmount = amountTransUtil.transAmount(wPaymentInfoDetailDTO.getPayAmount());
        wWechatPrePaymentRequestDTO.setTotal_fee(Integer.valueOf(tPayAmount));//总金额
        wWechatPrePaymentRequestDTO.setSpbill_create_ip(IpUtil.getLocalIP());//终端IP
        wWechatPrePaymentRequestDTO.setNotify_url(wechatConfig.getWechatNotifyUrl());//通知地址
        wWechatPrePaymentRequestDTO.setTrade_type("JSAPI");//交易类型
        wWechatPrePaymentRequestDTO.setOpenid(openid);//用户标识
        String sign = WechatSignUtil.getSign(wWechatPrePaymentRequestDTO.toMap(), wechatConfig.getWechatKey());
        wWechatPrePaymentRequestDTO.setSign(sign);//签名
        wWechatPrePaymentRequestDTO.createXml();
        //传输报文
        String requestXML = wWechatPrePaymentRequestDTO.getXml();
        logger.info("统一下单请求报文:" + requestXML);
        //统一下单请求
        String responseXML = HttpClientUtil.postJsonData(WechatPaymentConstants.ORDER_URL, requestXML, "utf-8");
        logger.info("统一下单返回报文:" + responseXML);
        //解析返回,并返回订单参数
        XStreamComponent xStreamComponent = XStreamComponent.newInstance();
        xStreamComponent.processAnnotations(WechatPrePaymentResultDTO.class);
        WechatPrePaymentResultDTO tWechatPrePaymentResultDTO = (WechatPrePaymentResultDTO) xStreamComponent.fromXML(responseXML);
        WechatPaymentResultDTO tWechatPaymentResultDTO = new WechatPaymentResultDTO();
        if ("SUCCESS".equals(tWechatPrePaymentResultDTO.getResult_code()) && "SUCCESS".equals(tWechatPrePaymentResultDTO.getReturn_code())) {
            String timeStamp = Long.toString(System.currentTimeMillis() / 1000);
            String nonceStr = tWechatPrePaymentResultDTO.getNonce_str();
            tWechatPaymentResultDTO.setAppId(tWechatPrePaymentResultDTO.getAppid());
            tWechatPaymentResultDTO.setTimeStamp(timeStamp);
            tWechatPaymentResultDTO.setNonceStr(nonceStr);
            tWechatPaymentResultDTO.setSignType("MD5");
            tWechatPaymentResultDTO.setPackages("prepay_id=" + tWechatPrePaymentResultDTO.getPrepay_id());
            StringBuffer sb = new StringBuffer();
            sb.append("appId=").append(tWechatPaymentResultDTO.getAppId());
            sb.append("&nonceStr=").append(tWechatPaymentResultDTO.getNonceStr());
            sb.append("&package=").append(tWechatPaymentResultDTO.getPackages());
            sb.append("&signType=").append(tWechatPaymentResultDTO.getSignType());
            sb.append("&timeStamp=").append(tWechatPaymentResultDTO.getTimeStamp());
            String paySign = sb.toString() + "&key=" + wechatConfig.getWechatKey();
            paySign = SecurityUtil.Md5(paySign).toUpperCase();
            tWechatPaymentResultDTO.setPaySign(paySign);
            tWechatPaymentResultDTO.setPayNo(payNo);
            tWechatPaymentResultDTO.setReturnCode("000000");//
            tWechatPaymentResultDTO.setPayAmount(wPaymentInfoDetailDTO.getPayAmount());
            String signature = Signature(nonceStr, payNo, timeStamp);
            tWechatPaymentResultDTO.setSignature(signature);
        } else {
            tWechatPaymentResultDTO.setReturnCode("111111");
            tWechatPaymentResultDTO.setReturnDesc(tWechatPrePaymentResultDTO.getReturn_msg());
        }
        return tWechatPaymentResultDTO;
    }
  • 微信支付页面支付

支付需要的才能参数:
> 这里是引用

引入微信js:<script type="text/javascript" charset="UTF-8" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>

<script type="text/javascript">
	function onBridgeReady() {
		var appId = $('#appId').val();
		var timeStamp = $('#timeStamp').val();
		var nonceStr = $('#nonceStr').val();
		var pk = $('#pk').val();
		var paySign = $('#paySign').val();
		var signature = $('#signature').val();
		var payNo = $('#payNo').val();
		var payAmount = $('#payAmount').val();
		var payNotify = $('#payNotify').val();
		var cancelNotify = $('#cancelNotify').val();
		var findNotifyUrl = $('#findNotifyUrl').val();
		var signType = $('#signType').val();
		WeixinJSBridge.invoke('getBrandWCPayRequest', {
			"appId" : appId, //公众号名称,由商户传入
			"timeStamp" : timeStamp, //时间戳,自1970年以来的秒数
			"nonceStr" : nonceStr, //随机串			
			"package" : 'prepay_id=' + pk,
			"signType" : signType, //微信签名方式:
			"paySign" : paySign
		//微信签名
		}, function(res) {
			// 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
			if (res.err_msg == "get_brand_wcpay_request:ok") {
				//微信返回的状态 成功:
				var data = {
					'returnCode' : 'SUCCESS',
					'payNo' : payNo,
					'payAmount' : payAmount
				};
				var notifyData = JSON.stringify(data);
				$.ajax({
					type : "POST",
					url : findNotifyUrl,
					dataType : "json",
					data : {
						"payNo" : payNo,
						"notifyData" : notifyData
					},
					success : function(data) {
						var notifyUrl = data.notifyUrl;
						//alert(notifyUrl+"?data="+notifyData+"+++++++++++++ss++++++++++++++++++++++=");
						notifyUrl = notifyUrl + "?data=" + notifyData;
						var isEncode = data.isEncode;
						if (isEncode == 'Y') {
							notifyUrl = encodeURI(notifyUrl);
						}
						//alert(notifyUrl);
						window.location.href = notifyUrl;
					},
					error : function() {
						alert(error);
					}
				})
			}
			//支付失败
			if (res.err_msg == "get_brand_wcpay_request:fail") {
				var data = {
					'returnCode' : 'FAIL',
					'payNo' : payNo,
					'payAmount' : payAmount
				};
				var notifyData = JSON.stringify(data);
				//ajax请求后台,查询商户对应回调地址
				$.ajax({
					type : "POST",
					url : findNotifyUrl,
					dataType : "json",
					data : {
						"payNo" : payNo,
						"notifyData" : notifyData
					},
					success : function(data) {
						var notifyUrl = data.notifyUrl;
						//alert(notifyUrl+"?data="+notifyData+"+++++++++++++ss++++++++++++++++++++++=");
						notifyUrl = notifyUrl + "?data=" + notifyData;
						var isEncode = data.isEncode;
						if (isEncode == 'Y') {
							notifyUrl = encodeURI(notifyUrl);
						}
						window.location.href = notifyUrl;
					},
					error : function() {
						alert(error);
					}
				})
			}
			//支付取消
			if (res.err_msg == "get_brand_wcpay_request:cancel") {
				//alert("微信支付页面取消");
				var data = {
					'returnCode' : 'CANCEL',
					'payNo' : payNo,
					'payAmount' : payAmount
				};
				var notifyData = JSON.stringify(data);
				$.ajax({
					type : "POST",
					url : cancelNotify,
					dataType : "json",
					data : {
						"payNo" : payNo,
						"notifyData" : notifyData
					},
					success : function(data) {
						var notifyUrl = data.notifyUrl;
						//alert(notifyUrl+"?data="+notifyData+"+++++++++++++ss++++++++++++++++++++++=");
						notifyUrl = notifyUrl + "?data=" + notifyData;
						var isEncode = data.isEncode;
						if (isEncode == 'Y') {
							notifyUrl = encodeURI(notifyUrl);
						}
						//alert("支付地址是:"+notifyUrl);
						window.location.href = notifyUrl;
					},
					error : function() {
					}
				})
			}
		});
	}
	function toPay() {
		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();
		}
	}
</script>

3. 业务流程图
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/pengjwhx/article/details/85683019