欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

微信支付接入,就差这一步

程序员文章站 2022-04-29 08:09:50
...

首先测试号是无法接入微信支付功能的。必需有公众号并开通支付功能,不会的可以让公司的商务帮你开通。

1. 公众号后台  找到“接口权限”选项,然后找到“网页授权获取用户基本信息”,点“修改”

微信支付接入,就差这一步


2.打开界面点“设置”

微信支付接入,就差这一步


3.添加网页授权域名,注意去掉“http://”

微信支付接入,就差这一步

将下载下来的MP_verify_qHZ4JkZ2soVXMEYX.txt文件放到Tomcatroot。放好后先试试能不能访问,启动tomcat,用chenyuan.tunnel.2bdata.com/MP_verify_qHZ4JkZ2soVXMEYX.txt看能不能正常显示,最好点击确认会提示到成功的。

微信支付接入,就差这一步

4.添加授权目录

微信支付接入,就差这一步


按图找到授权目录添加地址。添加授权必需精确到支付页面的父目录,而且如果父目录有子目录,子目录下也是不可以发起支付的,切记,切记。


5.看支付流程图:

微信支付接入,就差这一步

太多,太晕,简而言之,除被扫支付场景以外,商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再按扫码、JSAPI、APP等不同场景生成交易串调起支付。

前台先通知后台向微信服务器发起“生成预支付交易单”请求,后台正确获取数据再组织报文将数据返回给前端,前台再组织数据调用JSAPI接口把预支付交易单上的数据携带给微信服务器,后面就不用我们管了,微信服务器验证正确后会自动通知微信弹出输入密码框,微信服务器输入成功后会给前端返回成功还是失败值,同时把交易数据以post方式传给商户后台系统,链接是发预支付交易单请求时传的notifyUrl值,微信服务器不能保证向前端和后端返回的数据有先后顺序,一般情况下不用管。

先上代码,java后台收到前端要支付的请求,先发起预支付交易单请求:


@ApiOperation(value = "预付请求", notes = "预付请求")
	@ApiImplicitParams({ @ApiImplicitParam(name = "ordCd", value = "订单号", required = true, dataType = "String") })
	@RequestMapping(value = "ordPrePay", method = RequestMethod.GET)
	@ResponseBody
	public Object ordPrePay(@RequestParam(value = "ordCd", required = true) String ordCd, HttpServletRequest request) {
		try {
			UserInfo userInfo = (UserInfo) request.getSession().getAttribute("userInfo");
			if (null == userInfo) {
				ExpUtil.handle("未网页授权获得用户基本信息,请从微信首页进入!!", logger);
			}
			OrdDtox ordDtox = ordMgrx.getOrdByOrdCd(ordCd);

			if (null == ordDtox) {
				ExpUtil.handle("订单号【" + ordCd + "】查询失败,请确认!", logger);
			}
//weixin-java-mp.jar提供的API
			Map<String, String> payInfo = this.wxMpPayService.getPayInfo(WxPayUnifiedOrderRequest.builder()
					.body(ordDtox.getOrdVo().getWacNm() + "-" + ordDtox.getOrdVo().getNm())
					.totalFee(ordDtox.getOrdVo().getOrdAmt().multiply(new BigDecimal(100)).intValue())
					.spbillCreateIp(request.getRemoteAddr()).outTradeNo(ordDtox.getOrdVo().getCd())
					.openid((String) request.getSession().getAttribute("openId")).build());
			System.out.println(payInfo.toString());
			return payInfo;
		} catch (Throwable t) {
			return buildFailure(ExpUtil.capture(BaseSvcMsgCode.insertFailure, "下单失败", t, logger));
		}
	}

其中有些参数你以为没传吗,其实我在外部已经配了。

微信支付接入,就差这一步

将配置的参数存放到WxMpConfigStorage里,再将WxMpConfigStorage注入到WxMpService里,那就不会每次都添加appid等参数了。

其中:notifyURL的作用是:当前端调用WeixinJSBridge.getBrandWCPayRequest方法发请支付请求并支付成功后,微信服务器将参数通知的该地址,数据以POST携带。我们在些链接上做支付成功的后台逻辑操作,比如记录消费记录,修改订单详情等。

 

在预支付交易单里appid,macId,key不用设置,后台会WxMpConfigStorage里得到配置参数从配置文件里补充,nonceStr,sign可由java自动生成,如下
微信支付接入,就差这一步

看看unifiedOrder的方法。

微信支付接入,就差这一步

当关键参数没有时,会从config里取,注意对着api看哪些参数可以不用传,当然也可参照我上面写的例子。

如果返回:

<xml><return_code><![CDATA[FAIL]]></return_code>
<return_msg><![CDATA[appid and openid not match]]></return_msg>
</xml>

则说明,传的openId不是指定公众号下的用户,出现这种情况有可能开发时测试公众号与开发公众号混合开发了。

 

正确返回数据如下:

prePay返回给前端数据:

{appId=wxf81943674XXX, timeStamp=1494902640, signType=MD5, package=prepay_id=wx20170516104359f71cd93cc00819XXXX, nonceStr=1494902640216, paySign=0DFFC6C2A9319E718B5XXXXX}

成功返回给前端后,前端使用JSAPI里的WeixinJSBridge.getBrandWCPayRequest方法发请支付请求。

注意:WeixinJSBridge内置对象在其他浏览器中无效

前端支付请求代码如下:

//用ajax向后台发请预计交易支付请求,当后台成功获取数据返回给前端时,前端组织数据发请真正的扣款支付请求。
function payforNow() {
	var json = {};
	json["ordCd"] = vue.cd;
	jQuery.ajax({
		type: "GET",
		url: "../bss/pay/ordPrePay",
		xhrFields: {
			withCredentials: true
		},
		data: json,
		contentType: "application/x-www-form-urlencoded",
		dataType: "json",
		async: true,
		success: function (data) {
			prePayData = data;
//成功得到预支付交易数据
			doBridgeReady(data);
			console.log("appId:" + data.appId);
		},
		error: function (res) {
			console.log("ajax请求失败,res:" + res.toString());
		}
	});
}

//判断浏览器是否支持JSAPI,只用微信内置浏览器可用。
function doBridgeReady(data){
	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(data);
		} 
}

//真实支付请求
function onBridgeReady(data){
	   WeixinJSBridge.invoke(
	       'getBrandWCPayRequest', {
	    	   "appId" : data.appId, /* 微信支付,坑一 冒号是中文字符 */
	           "appId": data.appId,     //公众号名称,由商户传入     
	           "timeStamp": data.timeStamp,         //时间戳,自1970年以来的秒数     
	           "nonceStr": data.nonceStr, //随机串     
	           "package": data.package,     
	           "signType": data.signType,         //微信签名方式:     
	           "paySign": data.paySign //微信签名 
	       },
	       function(res){  
	           if(res.err_msg == "get_brand_wcpay_request:ok" ) {
	        	   window.location.href="../page/orderWaitTakeCloth.jsp";
	           }else{
	        	   alert("支付失败,提示【" + res.err_msg + "】");
	           }
	       }
	   ); 
}

微信服务器验证参数是否正确,如里正确则让微信客户端弹出输入密码框
微信支付接入,就差这一步

之后微信服务器验证成功则支付成功,并通知前端。

微信支付接入,就差这一步

返回get_brand_wcpay_request:cancel,get_brand_wcpay_request:fail请检查一下授权目录是否包含当前调用h5支付的目录。注意是精确,即使是子目录也没权限,必需授权。

 

notifyURL指定的接收微信服务器返回支付成功的数据:

@ApiOperation(value = "支付成功后台通知", notes = "支付成功后台通知")
	@RequestMapping(value = "paySuccessCallBack", method = RequestMethod.POST)
	@ControllerTraced(name = "支付成功后台通知")
	public Object paySuccessCallBack(HttpServletRequest request, HttpServletResponse response) throws IOException {
		try {
			String xmlData = textRequestStream(request);
//将post里的数据读取出来映射成class对象。后台的操作就是自己服务器的逻辑了。
			WxPayOrderNotifyResult wxPayOrderNotifyResult = this.wxMpPayService.getOrderNotifyResult(xmlData);
			//微信订单号,先判断该笔订单是否处理过,如果处理过,则直接返回
			PayLogDtox payLogDtox = payLogMgrx.getPayLogDtox(wxPayOrderNotifyResult.getTransactionId());
			if(null == payLogDtox){
				payMgrx.wxMpPayForSuccessCBack(wxPayOrderNotifyResult);
			}else{
				return WxPayOrderNotifyResponse.fail("收到重复消息");
			}
		} catch (WxErrorException e) {
			e.printStackTrace();
			return WxPayOrderNotifyResponse.fail(e.getMessage());
		}catch (Throwable t) {
    		// ExpUtil.capture(BaseSvcMsgCode.selectFailure,"保存失败", t, logger);
			logger.error("保存失败");
        }
		return WxPayOrderNotifyResponse.success("成功");
	}


结,第一,添加授权目录,而且要精确到支付页面的父目录

第二,自己后台服务器向微信服务器发请预支付交易请求,并将得到的数据传给前端

第三,前端使用WeixinJSBridge.getBrandWCPayRequest方法组织报文数据向微信服务器发起真正的支付请求,验证成功并扣款成功后,微信服务器会将数据通知到预支付交易里填写的notifyURL上。如果交易失败,请查看是否授权目录填写正确,大部分情况是这里出了问题。

第四,nofityURL接收支付数据并插入到数据库。

 

以上帮助大家了解过程,以及解决些bug,我还是要亲自去微信支付接入文档仔细阅读。

相关标签: 微信 支付