今天刚将小程序的支付调通,和大家分享下(坑)
源码下载:https://pan.baidu.com/s/1skQiXPz
包括小程序端、java服务器端
和其他方式的微信支付方式区别不大,也都需要经过统一下单、支付结果通知(回调),具体流程如下:
1、小程序内调用登录接口,获取到用户的openid,api参见公共api【小程序登录API】
2、商户server调用支付统一下单,api参见公共api【统一下单API】
3、商户server调用再次签名,api参见公共api【再次签名】
4、商户server接收支付通知,api参见公共api【支付结果通知API】
5、商户server查询支付结果,api参见公共api【查询订单API】
下面结合源码详解下流程:
第一步: 获取客户的openid
统一下单中需要用到openid
小程序:
首先需要调用微信登录接口获取用户的code:
var that = this; wx.login({ success: function(res) { that.getOpenId(res.code); } });
通过code获取openid:
//获取openid getOpenId: function(code){ var that = this; wx.request({ url: 'https://www.see-source.com/weixinpay/GetOpenId', method: 'POST', header: { 'content-type': 'application/x-www-form-urlencoded' }, data: {'code':code}, success: function(res) { var openId = res.data.openid; that.xiadan(openId); } }) }
java:
String code = request.getParameter("code"); HttpGet httpGet = new HttpGet("https://api.weixin.qq.com/sns/jscode2session?appid="+Configure.getAppID()+"&secret="+Configure.getSecret()+"&js_code="+code+"&grant_type=authorization_code"); //设置请求器的配置 HttpClient httpClient = HttpClients.createDefault(); HttpResponse res = httpClient.execute(httpGet); HttpEntity entity = res.getEntity(); String result = EntityUtils.toString(entity, "UTF-8"); response.getWriter().append(result);
第二步:统一下单
调用微信的统一下单接口,返回预订单id(prepay_id)
小程序:
var that = this; wx.request({ url: 'https://www.see-source.com/weixinpay/xiadan', method: 'POST', header: { 'content-type': 'application/x-www-form-urlencoded' }, data: {'openid':openId}, success: function(res) { var prepay_id = res.data.prepay_id; console.log("统一下单返回 prepay_id:"+prepay_id); that.sign(prepay_id); } })
java:
String openid = request.getParameter("openid"); OrderInfo order = new OrderInfo(); order.setAppid(Configure.getAppID()); order.setMch_id(Configure.getMch_id()); order.setNonce_str(RandomStringGenerator.getRandomStringByLength(32)); order.setBody("dfdfdf"); order.setOut_trade_no(RandomStringGenerator.getRandomStringByLength(32)); order.setTotal_fee(10); order.setSpbill_create_ip("123.57.218.54"); order.setNotify_url("https://www.see-source.com/weixinpay/PayResult"); order.setTrade_type("JSAPI"); order.setOpenid(openid); order.setSign_type("MD5"); //生成签名 String sign = Signature.getSign(order); order.setSign(sign); String result = HttpRequest.sendPost("https://api.mch.weixin.qq.com/pay/unifiedorder", order); System.out.println(result); L.info("---------下单返回:"+result); XStream xStream = new XStream(); xStream.alias("xml", OrderReturnInfo.class); OrderReturnInfo returnInfo = (OrderReturnInfo)xStream.fromXML(result); JSONObject json = new JSONObject(); json.put("prepay_id", returnInfo.getPrepay_id()); response.getWriter().append(json.toJSONString());
Notify_url 是支付完成后就收微信的通知的,告诉你用户是否付款了
注意:Total_fee单位是分,必须是整数,不能是小数
Trade_type字段对于小程序来说固定写成JSAPI
第三步:再次签名
这是小程序的不同之处,要求对拿到的repay_id进行再次签名。
注意这里有坑了:package字段的值是个键值对,格式prepay_id=12312333333333333
小程序:
var that = this; wx.request({ url: 'https://www.see-source.com/weixinpay/sign', method: 'POST', header: { 'content-type': 'application/x-www-form-urlencoded' }, data: {'repay_id':prepay_id}, success: function(res) { that.requestPayment(res.data); } })
java:
String repay_id = request.getParameter("repay_id"); SignInfo signInfo = new SignInfo(); signInfo.setAppId(Configure.getAppID()); long time = System.currentTimeMillis()/1000; signInfo.setTimeStamp(String.valueOf(time)); signInfo.setNonceStr(RandomStringGenerator.getRandomStringByLength(32)); signInfo.setRepay_id("prepay_id="+repay_id); signInfo.setSignType("MD5"); //生成签名 String sign = Signature.getSign(signInfo); JSONObject json = new JSONObject(); json.put("timeStamp", signInfo.getTimeStamp()); json.put("nonceStr", signInfo.getNonceStr()); json.put("package", signInfo.getRepay_id()); json.put("signType", signInfo.getSignType()); json.put("paySign", sign); L.info("-------再签名:"+json.toJSONString()); response.getWriter().append(json.toJSONString());
第四步:调起支付
最后一步调起小程序支付api
wx.requestPayment({ 'timeStamp': obj.timeStamp, 'nonceStr': obj.nonceStr, 'package': obj.package, 'signType': obj.signType, 'paySign': obj.paySign, 'success':function(res){ }, 'fail':function(res){ } })
之后就等着用户去输入支付密码完成支付了
还有个接口是查询订单,这个不是必须的,你根据需要使用