微信小程序开发

您所在的位置:网站首页 怎样取消微信付款码免密支付功能 微信小程序开发

微信小程序开发

2023-10-26 08:02| 来源: 网络整理| 查看: 265

微信小程序开发之---微信免密支付 很多时候我们都要用到免密支付,也就是常说的自动扣款,但是如何才能自动扣费,这一块微信api也没有详细说明,微信普通的支付官方说的很清楚,但是免密支付可就少了。。这类的支付的东西很多,比如滴滴打车、App Store微信支付、二维码乘车等。

下面是我做的一个项目,小程序、后台接口、数据库构建。二维码乘车,微信小程序生成二维码,公交机器上面安装卡机扫码扣费。上线四个月,我们用户量几十万,每天扫码订单数两万多,金额十来万。

image.png image.png image.png image.png image.png 图片发自简书App 需要准备的东西: 1、申请微信小程序号。 2、申请微信商户号(商户开通委托代扣,好像需要私下找微信走流程,我用的账号是甲方提供的)。 3、下载微信开发者工具。

按照下面图片进入开发者工具,创建好你的项目,根据图片选工具自动回给你创建项目目录,这一点就不详细说了。

一些发送的参数和结果我不会详细说,可以看下下面链接详细说明,这是我们和微信合作,微信人员给的api内部文档,免密支付(自动扣费)api文档地址:https://pay.weixin.qq.com/wiki/doc/api/pap.php?chapter=18_3&index=7 其实有了这个链接看看基本差不多懂了!。。。。。

接着往下看吧。

免密支付首先要和用户签订免密支付协议。怎么签?

首先需要用code查询用户openid。

如何获取code?

1、小程序用户登录就行。

//登录 wx.login({ success: function (res) { //res.code 然后就请求你的后台接口获取。 }, fail: function () { } })

2、通过用户登录获取的code,请求微信接口获取openid。 注 一个code只能用一次。 我用的是java获取用户openid 小程序不行,因为小程序请求必须填写安全url域名,微信的域名不能填写进去。所有放弃用小程序获取吧

private Map _getOpenId(String code){ Map ret = new HashMap(); Map urlData= new HashMap(); urlData.put("appid",appid);//小程序id urlData.put("secret",appKey);//小程序key urlData.put("grant_type","authorization_code");//固定值这样写就行 urlData.put("js_code",code);//小程序传过来的code HttpsClientUtil httpsClientUtil = new HttpsClientUtil(); Object data_deserialize = null; try { //code2OpenidUrl "https://api.weixin.qq.com/sns/jscode2session"; String dataStr = httpsClientUtil.doGet(code2OpenidUrl, urlData); data_deserialize = JSONUtil.deserialize(dataStr); }catch(Exception ex){ ret.put("success", false); ret.put("msg", "_getOpenId_未知异常"); ret.put("message", ex); return ret; } Map data= (Map)data_deserialize; if( data.containsKey("errcode") ){ ret.put("success", false); ret.put("msg", data.containsKey("errcode")); ret.put("message", data.containsKey("errmsg")); }else{ ret.put("success", true); ret.put("result",data); } return ret; } 好了,开始签约吧。签约只需要小程序即可,不需要后台做什么。

首先需要app发起签约请求,这个是签约的方法, 不过首先要把 签约小程序放在 app.json中 这是微信新的规则

"navigateToMiniProgramAppIdList": [ "wxbd687630cd02ce1d", 签约小程序 "wx5e73c65404eee268" 微信代付 用户还款小程序 ]

wxml

//bindGetUserInfo 是我的逻辑函数,不需要看, 立即绑定

js

//发起签约请求 data里面传值是必须传的几项,没强制要求的我没传 var me = this; //装作参数 this.globalData.contract_code = this.genID(5); var data = { mch_id: this.globalData.mch_id,//你的商户号 appid: this.globalData.appid,//小程序appid plan_id: this.globalData.plan_id,//你的商户签约模板id(在商户号里面设置) contract_code: this.globalData.contract_code, //签约码,商家生成,商户侧须唯一 contract_display_account: this.turnNickName(this.globalData.userInfo["nickName"]||""), //签约用户名称,我这里用的是用户微信名字(怎么获取下面有)本来我想用手机号的,但是获取手机号需要注册或者是微信api获取需要用户点击同意,甲方说用户多操作一步用户体验不好。。。 notify_url: "https://www.***.com/contractNotify",// 签约成功与否微信返回数据的接收地址 request_serial: ((new Date()).getTime() - 1526353000000),//商户请求签约时的序列号纯数字,长度不超过12位 timestamp: parseInt((new Date()).getTime() / 1000) + "" //时间戳 }; //签名 MD5加密 data.sign = util.genSign(data, this.globalData.key); //开始发起签约 wx.navigateToMiniProgram({ appId: 'wxbd687630cd02ce1d', //固定值,这个是填写微信官方签约小程序的id extraData: data, path: 'pages/index/index', success(res) { wx.setStorageSync('contract_id', ""); me.globalData.contract_id = ""; // 成功跳转到签约小程序 }, fail(res) { console.log(res); // 未成功跳转到签约小程序 } });

签约后会返回一些签约信息,在app.js文件中 onShow函数中获取。 这里面需要注意的是,用户点击的是返回还是点击左上角的X。。。 我是当用户点击签约按钮时候,就开启一个定时器去监控,onShow里面取后台数据库查询签约状态,(微信会把签约结果异步通知到notify_url,在里面存到数据库就行)

App({ onShow(res) { if (res.scene === 1038) { // 场景值1038:从被打开的小程序返回 const { appId, extraData } = res.referrerInfo if (appId == 'wxbd687630cd02ce1d') { // appId为wxbd687630cd02ce1d:从签约小程序跳转回来 if (typeof extraData == 'undefined'){ // TODO ***用户击左上角的返回*** // 客户端小程序不确定签约结果,需要向商户侧后台请求确定签约结果 return; } if(extraData.return_code == 'SUCCESS'){ // TODO // 客户端小程序签约成功,需要向商户侧后台请求确认签约结果 var contract_id = extraData.contract_id return; } else { // TODO // 签约失败 return; } } } } }) notify_url函数,用来接收用户签约微信返回的结果xml

注意:只要收到微信通知,你就必须返回结果

失败: 成功: // 接收发起免密签约后小程序返回的结果接口 public String contractNotify() throws Exception{ StringBuilder sb = new StringBuilder(); BufferedReader reader = request.getReader(); char[]buff = new char[1024]; int len; while((len = reader.read(buff)) != -1) { sb.append(buff,0, len); } String wxResponseText = sb.toString(); // rootLogger.info("收到contractNotify"); //开始解析xml字符串 Document document = DocumentHelper.parseText(wxResponseText); Element root = document.getRootElement(); Element successEl=root.element("return_code");//查询状态 String success=successEl.getStringValue(); Element return_msgEl; String return_msg=""; if(success.equals("SUCCESS")){ Element resultCodeEl=root.element("result_code");//查询状态 String resultCode=resultCodeEl.getStringValue(); if(resultCode.equals("SUCCESS")){ Element contractCodeEl=root.element("contract_code");//查询状态 String contractCode=contractCodeEl.getStringValue(); Element openidEl=root.element("openid");//openid String openid=openidEl.getStringValue(); Element contractIDEl=root.element("contract_id");//签约id String contractID=contractIDEl.getStringValue(); Element operateTimeEl=root.element("operate_time");//签约操作时间 String operateTime=operateTimeEl.getStringValue(); Element changTypeEl=root.element("change_type");//签约操作时间 String changType=changTypeEl.getStringValue(); //申明储存数据对象 Map contractData = new HashMap(); contractData.put("openid",openid); contractData.put("contract_id",contractID); contractData.put("contract_code",contractCode); contractData.put("create_time",operateTime);//如果是插入就当create_time存 contractData.put("update_time",operateTime);//如果是修改就当update_time存 contractData.put("chang_type",changType);//如果是修改就当update_time存 //开始储存 //先查询有没有,存放查询结果 List queryList = null; try{ queryList = dbExecutor.query("com.sutpc.dao.PayDao.selectContract", contractData);//list.get(0).get(contract_id); }catch (Exception e){ rootLogger.error("contractNotify--query----查询失败!"); rootLogger.error(e); return "success"; } //判断查询结果 如果有就修改 如果没有就插入 if( queryList==null || queryList.size()==0 ){ try{ dbExecutor.insert("com.sutpc.dao.PayDao.saveContract", contractData); }catch (Exception e){ rootLogger.error("contractNotify---insert---储存失败!"); rootLogger.error(e); return "success"; } }else{ try{ dbExecutor.update("com.sutpc.dao.PayDao.updateContract", contractData); }catch (Exception e){ rootLogger.error("contractNotify---update---储存失败!"); rootLogger.error(e); return "success"; } } } }else{ return_msgEl=root.element("return_msg");//查询状态 return_msg=return_msgEl.getStringValue(); } // rootLogger.info("完成 contracttify"); return "success"; } 其中用到的用户微信名称,是通过微信api获取的 获取用户信息 wxml*** 立即绑定 js*** //如果用户第一次使用我们程序,获取用户信息必须要用户点击按钮同意后才行,以后就不需要了,商家直接获取就行 bindGetUserInfo: function (e) { if (!app.globalData.userInfo){ //新用户判断是否同意绑定 if (e.detail.userInfo){ app.globalData.userInfo = e.detail.userInfo; this.setData({ userInfo: e.detail.userInfo, hasUserInfo: true }) //已授权开始绑定 this.bindBtnBangDing(); }else{ wx.showToast({ title: '您未同意授权', image: '../../images/shangxin.png', duration: 1000, mask: true }); } } },

到以上,签约已经成功了,当需要扣款时,就可以用用户的contract_id进行扣款了(如:扫码乘车,滴滴打车等,我们是扫码乘车用),不论什么时候扣,都能直接成功,用户会收到一条微信支付消息。

那么如何扣款? 接下来就是java干的事情了,当需要扣用户费用时候,后台服务调用申请扣款接口即可。 组装一些必要的参数,然后向微信API发起扣款请求即可,那么需要什么参数?可以看最上面我放的链接!详细的接口介绍!

请求appid、商户号、随机字符串、签名(我用的是MD5)、商品描述、商户订单号、总金额、终端IP(发起扣款电脑ip,运行程序的服务器地址)、回调通知url(接收XML扣款结果地址)、交易类型(填PAP微信委托代 扣支付)、委托代扣协议id(用户签约的contract_id) 这些是必须传的,没有强制要求的我们传,我懒。

我用的是java写的。

注:以下这些微信API需要传输的详细参数看上面我放的链接。我只传了一些必须传的值。 首先解释下一些全局变量是什么: // 一些微信接口api地址----- // 请求扣款 private String wxPayApplyUrl = "https://api.mch.weixin.qq.com/transit/pay/payapply"; // 查询openid private String code2OpenidUrl="https://api.weixin.qq.com/sns/jscode2session"; // 查询订单状态 private String wxQueryOrderUrl="https://api.mch.weixin.qq.com/pay/paporderquery"; // 查询用户状态 private String wxQueryStateUrl="https://api.mch.weixin.qq.com/transit/pay/querystate"; // 查询contract_id private String wxQueryContractUrl="https://api.mch.weixin.qq.com/papay/querycontract"; // 发起退款 private String wxRefundUrl="https://api.mch.weixin.qq.com/secapi/pay/refund"; // 查询退款 private String wxSelectRefund="https://api.mch.weixin.qq.com/pay/refundquery"; // 请求微信接口固定常量 private final String mch_id="***"; //商户号 private final String plan_id="***";//签约模板id号 private final String appid="***";//小程序号 private final String trade_type="PAP";//这个填固定值 private final String notify_url="***";//接收返回结果的地址 private final String appKey="***";//小程序app的key private final String signKey="***";//签名的KEY,每个商户号一个,可以重置,但是需要严格保密。

注:注意用户打开小程序最好查询一下用户状态有没有支付能力,有没有欠费(用户如果钱不够,微信会帮用户垫资一次,需要用户去微信支付点击还款,如果不还款,用户就使用不了免密支付)

查询用户状态函数, 查看用户是否欠费。有没有支付能力。 private Map _queryState(String openid, String contract_id){ //将所有参数组装成map排序 Map signMap = new TreeMap( new Comparator() { public int compare(String obj1, String obj2) { // 升序排序 return obj1.compareTo(obj2); } } ); signMap.put("appid",appid); signMap.put("mch_id",mch_id); //生成随机字符串 String nonce_str= MD5Utils.getNonceStr(32); signMap.put("nonce_str",nonce_str); signMap.put("contract_id",contract_id); signMap.put("sign_type","MD5"); signMap.put("openid",openid); //获取签名结果 String sign=getSign(signMap); //拼接XML StringBuilder XML = new StringBuilder(); XML.append(""); XML.append(""); XML.append(""); XML.append(""); XML.append(""); XML.append(""); XML.append(""); XML.append(""); XML.append(""); String xml = XML.toString(); // 调用请求微信接口函数 并return结果 HttpsClientUtil httpsClientUtil = new HttpsClientUtil(); Document document = null; try { String wxResponseText = httpsClientUtil.doPostXml(wxQueryStateUrl, xml); //开始解析xml字符串,验证签名我就不写这里了,删除了,太长了!你们注意别忘记验证消息安全性。 document = DocumentHelper.parseText(wxResponseText); }catch (Exception ex){ results.put("success",false); results.put("msg", "_queryState 发生异常"); results.put("message", ex); return results; } Element root = document.getRootElement(); Element successEl=root.element("return_code");//查询状态 String success=successEl.getStringValue(); //开始判断结果 if(success.equals("SUCCESS")){//判断查询状态 Element resultCodeEL=root.element("result_code"); //业务结果 String resultCode=resultCodeEL.getStringValue(); if( resultCode.equals("SUCCESS") ){//判断业务结果 //存放结果数据 Map item= new HashMap(); //用户状态 Element userStateEl=root.element("user_state"); String userState=userStateEl.getStringValue(); String contractState=""; if( userState.equals("NORMAL") ){//允许 item.put("user_state", 0); //签约状态 0 签约中 1 解约 Element contractStateEl=root.element("contract_state"); contractState=contractStateEl.getStringValue(); }else if( userState.equals("BLOCKED") ){//不允许 item.put("user_state", 1); //签约状态 0 签约中 1 解约 Element contractStateEl=root.element("contract_state"); contractState=contractStateEl.getStringValue(); }else if( userState.equals("OVERDUE") ){//用户欠费 item.put("user_state", 2); contractState="0"; } item.put("contract_state", contractState); results.put("result",item); results.put("success", true); }else if( resultCode.equals("FAIL") ){ Element errCodeEl=root.element("err_code");//错误代码 String errCode=errCodeEl.getStringValue(); Element errCodeDesEl=root.element("err_code_des");//错误代码描述 String errCodeDes=errCodeDesEl.getStringValue(); results.put("success",false); results.put("msg",errCode); results.put("message", errCodeDes); } }else if(success.equals("FAIL")){ Element msgEl=root.element("return_msg");//错误原因 String msg=msgEl.getStringValue(); results.put("success",false); results.put("msg",msg); } return results; }

发起扣款函数,签名我用的是MD5加密签名,这里需要注意的是签名的key是你商户号里面的key,注意保密。签名之前,参数需要排好序123 、abc等不多说。注意,给微信传的必须是XML字符串

至于md5加密方法网上可以找,这个是我的 //首先,这是我的MD5加密类 package com.sutpc.utils; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Random; public class MD5Utils { private static final String DIGEST_ALGORITHM = "MD5"; private static final char HEX_DIGITS[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; public static final String md5(String msg) { if (msg == null) { return null; } MessageDigest md5 = null; try { md5 = MessageDigest.getInstance(DIGEST_ALGORITHM); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } if (md5 == null) { return null; } try { md5.update(msg.getBytes("utf-8")); }catch(Exception ex){} byte[] digest = md5.digest(); return byte2Hex(digest); } public static String getNonceStr(int length){ String base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; Random random = new Random(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < length; i++) { int number = random.nextInt(base.length()); sb.append(base.charAt(number)); } return sb.toString(); } private static final String byte2Hex(byte[] b) { int j = b.length; char str[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = b[i]; str[k++] = HEX_DIGITS[byte0 >>> 4 & 0xf]; str[k++] = HEX_DIGITS[byte0 & 0xf]; } return new String(str); } /** * @param args */ public static void main(String[] args) { System.out.println(MD5Utils.md5(null)); System.out.println(MD5Utils.md5("Ngis_Admin_3975528")); System.out.println(MD5Utils.md5("111111")); System.out.println(MD5Utils.md5("")); System.out.println(MD5Utils.md5("123")); System.out.println(MD5Utils.md5("12dsafasf3")); System.out.println(MD5Utils.md5("全是有工在以有")); System.out.println(MD5Utils.md5("全是有工在以有")); System.out.println(MD5Utils.md5("1")); } } //其次,这是我的加密函数 。传入排序后map,生成签名 public String getSign(Map signMap){ //组装md5签名字符串 String sign=""; for(String nameKey:signMap.keySet()){ sign += nameKey+"="+signMap.get(nameKey)+"&"; } sign+="key="+signKey; //调用md5签名方法 return MD5Utils.md5(sign).toUpperCase(); }

这个是我组装发起扣款的函数,前面获取各种参数每个程序不同我没放进去。 这里面需要注意:contract_id 是用户免密签约时微信给的, 但是如果用户解约了、在签约这个值会重新变,所有我扣款时每次找微信查,以防出错。 你可以用你用户签约时你在数据库存的。 这里说一下,请求微信查询contract_id时,我们用户有几十万,其中有一两个用户信息获取contract_id时候微信接口返回请求超时,让我们重复请求,但是依旧是超时,所以从我们数据库获取这两个用户签约信息。 信息保存很重要吧。。 api:"https://api.mch.weixin.qq.com/transit/pay/payapply"

发起扣款接口 // 传入组装好的的参数,请求微信接口发起扣款申请 public String doWxPay(Map paramMap) throws Exception { // **** 从传入对象中获取值 String sign_type="MD5"; String sign; String body="公交乘车代扣"; String nonce_str= MD5Utils.getNonceStr(32);//随机字符串 String start_time= (String) paramMap.get("start_time");//下车时间 String end_time= (String) paramMap.get("end_time");//下车时间 String line_name= (String) paramMap.get("lineName");//线路名称 String openid= (String) paramMap.get("openid");//订单号 String out_trade_no= (String) paramMap.get("orderNo"); int total_fee = (int) paramMap.get("total_fee");//微信传输单位为分 String spbill_create_ip= InetAddress.getLocalHost().getHostAddress();//获取本机ip String scene_info; String trade_scene; if( paramMap.containsKey("start_stationName") && paramMap.containsKey("end_stationName") ){ //我们有两种场景 地铁和公交 你们看情况用 String start_stationName=line_name +"("+(String) paramMap.get("start_stationName"); if(start_stationName.length()>32){ start_stationName=start_stationName.substring(0,32); } String end_stationName= (String) paramMap.get("end_stationName") + ")"; if(end_stationName.length()>32){ end_stationName=end_stationName.substring(0,32); } //地铁场景 上车时间+下车时间+上车站点+下车站点 trade_scene="METRO"; //扣款用的是下车时间 scene_info="{\"scene_info\":{\"start_time\":\""+start_time+"\",\"end_time\":\""+end_time+"\",\"start_station\":\""+start_stationName+"\",\"end_station\":\""+end_stationName+"\"}}"; }else{ //公交场景 上车时间+线路名称 trade_scene="BUS"; scene_info="{\"scene_info\":{\"start_time\":\""+end_time+"\",\"line_name\":\""+line_name+"\"}}"; } // **** 开始获取contract_code String contract_id; Map contract_query_rtn = _queryContract(openid); if((boolean)contract_query_rtn.get("success")){ contract_id = (String)contract_query_rtn.get("contract_id"); }else{ //用openid查contract,微信返回错误 此错误是 系统超时 提示让重复查询 但是重复也一直查不到,所有去数据库查 如果查到就赋值,下面回去查用户状态。 if(contract_query_rtn.get("message").equals("SYSTEM ERROR")){ Map selectData= new HashMap(); selectData.put("openid",openid); List queryList = null; try{ queryList = dbExecutor.query("com..selectContract", selectData); if(queryList.size()>0){ contract_id= (String) queryList.get(0).get("contract_id"); }else{ throw new Exception("数据库中无此用户contract_id!"); } }catch (Exception e){ throw new Exception("从数据库查询contract_id失败!"); } }else{ throw new Exception("微信查询contract_id失败!"); } } // **** 开始储存订单到数据库 支付结果等微信回执中更改 try{ dbExecutor.insert("com.sutpc.base.dao.PayDao.saveOrder", paramMap); }catch (Exception e){ rootLogger.error("doWxPay-----存储失败!"); rootLogger.error(e); } // **** 将所有参数组装成map排序 Map signMap = new TreeMap( new Comparator() { public int compare(String obj1, String obj2) { // 升序排序 return obj1.compareTo(obj2); } }); signMap.put("sign_type",sign_type); signMap.put("body",body); signMap.put("nonce_str",nonce_str); signMap.put("out_trade_no",out_trade_no); signMap.put("total_fee",total_fee); signMap.put("spbill_create_ip",spbill_create_ip); signMap.put("contract_id",contract_id); signMap.put("scene_info",scene_info); signMap.put("mch_id",mch_id); signMap.put("appid",appid); signMap.put("notify_url",notify_url); signMap.put("trade_type",trade_type); signMap.put("trade_scene",trade_scene); //调用组合签名字符串函数,获取签名结果 sign=getSign(signMap); // ****: 开始拼接xml StringBuilder XML = new StringBuilder(); XML.append(""); XML.append(""); XML.append(""); XML.append(""); XML.append(""); XML.append(""); XML.append(""); XML.append(""); XML.append(""); XML.append(""); XML.append(""); XML.append(""); XML.append(""); XML.append(""); XML.append(""); XML.append(""); String xml = XML.toString(); rootLogger.info(xml); // ****: 调用请求微信接口函数 并return结果 HttpsClientUtil httpsClientUtil = new HttpsClientUtil(); return httpsClientUtil.doPostXml(wxPayApplyUrl, xml); } 自己写的发送请求方法,每个人每个库都不一样。 public String doPostXml(String url, String xml) throws Exception{ String result = null; HttpClient httpClient = new SSLClient(); HttpPost httpPost = new HttpPost(url); httpPost.addHeader("Content-Type","text/xml;"); StringEntity stringEntity = new StringEntity(xml, "UTF-8"); stringEntity.setContentEncoding("UTF-8"); httpPost.setEntity(stringEntity); HttpResponse response = httpClient.execute(httpPost); if(response != null){ HttpEntity resEntity = response.getEntity(); if(resEntity != null){ result = EntityUtils.toString(resEntity, "UTF-8"); } } return result; } 这个请求返回的结果也是一个XML,那么你就要解析这个结果,我用的是java的包 dom4j 非常好用。 //开始解析xml字符串 Document document = DocumentHelper.parseText(wxResponseText); Element root = document.getRootElement(); Element successEl = root.element("return_code"); String success = successEl.getStringValue(); Element msgEl = root.element("return_msg"); String msg = msgEl.getStringValue();//getTextTrim //开始判断结果 if (success.equals("SUCCESS")) {//判断握手结果 Element resultCodeEl = root.element("result_code"); String resultCode = resultCodeEl.getStringValue(); if (resultCode.equals("SUCCESS")) {//判断业务结果 item.put("success", true); } else { Element errCodeEl = root.element("err_code");//错误代码 String errCode = errCodeEl.getStringValue(); Element errCodeDesEl = root.element("err_code_des");//错误代码描述 String errCodeDes = errCodeDesEl.getStringValue(); item.put("success", false); item.put("msg", errCode); // **** 付款失败更新订单状态 // 如果错误状态是 ORDERPAID(订单已支付 订单号重复)就不更新。 if (!errCode.equals("ORDERPAID")) { //付款失败 更新订单状态以及错误码 itemParam.put("trade_state", resultCode); itemParam.put("err_code", errCode); itemParam.put("err_code_des", errCodeDes); sqlSession.update("com..updateOrder", itemParam); //付款失败 开始储存付款失败订单 this.saveFailOrder(itemParam); } } } else { item.put("success", false); item.put("msg", msg); // **** 请求失败更新订单状态 // 如果错误状态是 ORDERPAID(订单已支付 订单号重复)就不更新。 if (!msg.equals("ORDERPAID")) { //付款失败 更新订单状态以及错误码 itemParam.put("trade_state", success); itemParam.put("err_code", msg); sqlSession.update("com.sutpc.dao.PayDao.updateOrder", itemParam); //付款失败 开始储存付款失败订单 this.saveFailOrder(itemParam); } } 发起扣款时,填写的notify_url接口函数 用来接收请求微信扣款后,微信异步返回的结果通知xml // 接收发起扣款后小程序返回的结果接口 public String payNotify() throws Exception{ StringBuilder sb = new StringBuilder(); BufferedReader reader = request.getReader(); char[]buff = new char[1024]; int len; while((len = reader.read(buff)) != -1) { sb.append(buff,0, len); } String wxResponseText = sb.toString(); // rootLogger.info("收到paynotify"); //开始解析xml字符串 Document document = DocumentHelper.parseText(wxResponseText); Element root = document.getRootElement(); Element successEl=root.element("return_code");//查询状态 String success=successEl.getStringValue(); Element return_msgEl; String return_msg=""; if(success.equals("SUCCESS")){ Element resultCodeEl=root.element("result_code");//查询状态 String resultCode=resultCodeEl.getStringValue(); Element tradeStateEl=root.element("trade_state");//订单状态 SUCCESS 成功 PAY_FAIL 失败 String tradeState=tradeStateEl.getStringValue(); Element orderNoEl=root.element("out_trade_no");//商户订单号 String orderNo=orderNoEl.getStringValue(); Element transactionIdEl=root.element("transaction_id");//微信订单号time_end String transactionId=transactionIdEl.getStringValue(); Element timeEndEl=root.element("time_end");//time_end String timeEnd=timeEndEl.getStringValue(); //以防扫码时候存订单没存上 所有多放点数据 一遍插入时候使用 正常情况肯定都是修改updateOrder 但是以防万一 Element openidEl=root.element("openid");//time_end String openid=openidEl.getStringValue(); Element totalFeeEl=root.element("total_fee");//金额 String totalFee=totalFeeEl.getStringValue(); int totalFeeInt=Integer.parseInt(totalFee);//转成int //申明储存数据对象 Map orderData = new HashMap(); orderData.put("trade_state",tradeState);//订单状态 orderData.put("orderNo",orderNo);//订单号 orderData.put("transactionId",transactionId);//微信付款订单号 orderData.put("pay_time",timeEnd);//正常应该是修改 orderData.put("openid",openid);//用户id orderData.put("total_fee",totalFeeInt);//最终付款金额 String err_code=""; String err_code_des=""; if( resultCode.equals("FAIL") ){ try{ Element err_codeEl=root.element("err_code");//商户订单号 err_code=err_codeEl.getStringValue(); Element err_code_desEl=root.element("err_code_des");//微信订单号time_end err_code_des=err_code_desEl.getStringValue(); }catch (Exception e){ rootLogger.error("payNotify------解析结果时发送异常!"); rootLogger.error(wxResponseText); rootLogger.error(e); return "success"; } } // TODO 如果付款失败,且错误状态是 ORDERPAID(订单已支付 订单号重复)就不更新。 if(err_code.equals("ORDERPAID")){ return "success"; } orderData.put("err_code",err_code);//如果付款失败记录原因 orderData.put("err_code_des",err_code_des);//如果付款失败记录原因 //开始储存 //先查询有没有,存放查询结果 List queryList = null; try{ queryList = dbExecutor.query("com.sutpc.dao.PayDao.selectOrder", orderData); }catch (Exception e){ rootLogger.error("payNotify-----query---查询订单时发生未知异常!"); rootLogger.error(e); return "success"; } //判断查询结果 如果有就修改 如果没有就插入 if( queryList==null || queryList.size()==0 ){ try{ dbExecutor.insert("com.sutpc.dao.PayDao.saveOrder", orderData); }catch (Exception e){ rootLogger.error("payNotify---insert-----添加订单时发生异常!"); rootLogger.error(e); return "success"; } }else{ try{ dbExecutor.update("com.sutpc.dao.PayDao.updateOrder", orderData); }catch (Exception e){ rootLogger.error("payNotify----update---修改订单支付状态时发送异常!"); rootLogger.error(e); return "success"; } } }else{ return_msgEl=root.element("return_msg");//查询状态 return_msg=return_msgEl.getStringValue(); } // rootLogger.info("完成 paynotify"); return "success"; //return ""; }

扣款的就这些,你根据我上面放的api文档链接看步骤来就行,实在看不懂抄我的这个也行,自己弄好参数传过来。 注:不论是签约还是发起扣款申请,里面填写的notify_url你必须写好接口接收微信异步发送回来的数据,而且只要收到后,就必须回复,不然微信会一直高频率的给你发,直到你的服务器爆炸。。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3