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

来源:互联网 发布:药店进销存软件免费版 编辑:程序博客网 时间:2024/06/07 15:37

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

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)@ResponseBodypublic 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提供的APIMap<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,我还是要亲自去微信支付接入文档仔细阅读。
微信接入官方文档

原创粉丝点击