小程序支付详解+源码(客户端+服务端)

小程序的支付调通,和大家分享下(坑) 包括小程序端、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:

1.var that = this;
2.wx.login({
3.success: function(res) {
4.that.getOpenId(res.code);
5.}
6.});

通过code获取openid:

01.//获取openid
02.getOpenId: function(code){
03.var that = this;
04.wx.request({ 
05.url: 'https://www.see-source.com/weixinpay/GetOpenId', 
06.method: 'POST',
07.header: {
08.'content-type': 'application/x-www-form-urlencoded'
09.},
10.data: {'code':code},
11.success: function(res) {
12.var openId = res.data.openid;
13.that.xiadan(openId);
14.}
15.})
16.}
Java:
1.String code = request.getParameter("code");
2.HttpGet httpGet = new HttpGet("https://api.weixin.qq.com/sns/jscode2session?appid="+Configure.getAppID()+"&secret="+Configure.getSecret()+"&js_code="+code+"&grant_type=authorization_code");
3.//设置请求器的配置
4.HttpClient httpClient = HttpClients.createDefault();
5.HttpResponse res = httpClient.execute(httpGet);
6.HttpEntity entity = res.getEntity();
7.String result = EntityUtils.toString(entity, "UTF-8");
8.response.getWriter().append(result);

第二步:统一下单

调用微信的统一下单接口,返回预订单id(prepay_id) 小程序:

01.var that = this;
02.wx.request({
03.url: 'https://www.see-source.com/weixinpay/xiadan', 
04.method: 'POST',
05.header: {
06.'content-type': 'application/x-www-form-urlencoded'
07.},
08.data: {'openid':openId},
09.success: function(res) {
10.var prepay_id = res.data.prepay_id;
11.console.log("统一下单返回 prepay_id:"+prepay_id);
12.that.sign(prepay_id);
13.}
14.})

Java:

01.String openid = request.getParameter("openid");
02.OrderInfo order = new OrderInfo();
03.order.setAppid(Configure.getAppID());
04.order.setMch_id(Configure.getMch_id());
05.order.setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
06.order.setBody("dfdfdf");
07.order.setOut_trade_no(RandomStringGenerator.getRandomStringByLength(32));
08.order.setTotal_fee(10);
09.order.setSpbill_create_ip("123.57.218.54");
10.order.setNotify_url("https://www.see-source.com/weixinpay/PayResult");
11.order.setTrade_type("JSAPI");
12.order.setOpenid(openid);
13.order.setSign_type("MD5");
14.//生成签名
15.String sign = Signature.getSign(order);
16.order.setSign(sign);
17. 
18.String result = HttpRequest.sendPost("https://api.mch.weixin.qq.com/pay/unifiedorder", order);
19.System.out.println(result);
20.L.info("---------下单返回:"+result);
21.XStream xStream = new XStream();
22.xStream.alias("xml", OrderReturnInfo.class); 
23. 
24.OrderReturnInfo returnInfo = (OrderReturnInfo)xStream.fromXML(result);
25.JSONObject json = new JSONObject();
26.json.put("prepay_id", returnInfo.getPrepay_id());
27.response.getWriter().append(json.toJSONString());

Notify_url 是支付完成后就收微信的通知的,告诉你用户是否付款了 注意:Total_fee单位是分,必须是整数,不能是小数 Trade_type字段对于小程序来说固定写成JSAPI

第三步:再次签名

这是小程序的不同之处,要求对拿到的repay_id进行再次签名。 注意这里有坑了:package字段的值是个键值对,格式prepay_id=12312333333333333

小程序:

01.var that = this;
02.wx.request({
03.url: 'https://www.see-source.com/weixinpay/sign', 
04.method: 'POST',
05.header: {
06.'content-type': 'application/x-www-form-urlencoded'
07.},
08.data: {'repay_id':prepay_id},
09.success: function(res) {
10.that.requestPayment(res.data);
11. 
12.}
13.})

java:

01.String repay_id = request.getParameter("repay_id");
02.SignInfo signInfo = new SignInfo();
03.signInfo.setAppId(Configure.getAppID());
04.long time = System.currentTimeMillis()/1000;
05.signInfo.setTimeStamp(String.valueOf(time));
06.signInfo.setNonceStr(RandomStringGenerator.getRandomStringByLength(32));
07.signInfo.setRepay_id("prepay_id="+repay_id);
08.signInfo.setSignType("MD5");
09.//生成签名
10.String sign = Signature.getSign(signInfo);
11. 
12.JSONObject json = new JSONObject();
13.json.put("timeStamp", signInfo.getTimeStamp());
14.json.put("nonceStr", signInfo.getNonceStr());
15.json.put("package", signInfo.getRepay_id());
16.json.put("signType", signInfo.getSignType());
17.json.put("paySign", sign);
18.L.info("-------再签名:"+json.toJSONString());
19.response.getWriter().append(json.toJSONString());

第四步:调起支付

最后一步调起小程序支付api

01.wx.requestPayment({
02.'timeStamp': obj.timeStamp,
03.'nonceStr': obj.nonceStr,
04.'package': obj.package,
05.'signType': obj.signType,
06.'paySign': obj.paySign,
07.'success':function(res){
08.},
09.'fail':function(res){
10.}
11.})

之后就等着用户去输入支付密码完成支付了

还有个接口是查询订单,这个不是必须的,你根据需要使用

下载源码

原文发布于微信公众号 - 极乐技术社区(wxapp-union)

原文发表时间:2017-06-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏我有一个梦想

设计模式学习笔记-命令模式

1. 概述   将一个请求封装为一个对象(即我们创建的Command对象),从而使你可用不同的请求对客户进行参数化; 对请求排队或记录请求日志,以及支持可撤销的...

205100
来自专栏Core Net

ASP.NET Core 2.1 : 十四.静态文件与访问授权、防盗链

我的网站的图片不想被公开浏览、下载、盗链怎么办?本文主要通过解读一下ASP.NET Core对于静态文件的处理方式的相关源码,来看一下为什么是wwwroot文件...

18220
来自专栏程序你好

不同的.Net版本客户端软件调用Java Web Service区别

最近的系统中需要.Net开发的离线端软件通过Web Service技术和Java开发的在线系统进行数据交互。

12130
来自专栏恰童鞋骚年

设计模式的征途—19.命令(Command)模式

在生活中,我们装修新房的最后几道工序之一是安装插座和开关,通过开关可以控制一些电器的打开和关闭,例如电灯或换气扇。在购买开关时,用户并不知道它将来到底用于控制什...

7120
来自专栏智能大石头

NewLife.Redis基础教程

X组件缓存架构以ICache接口为核心,包括MemoryCache、Redis和DbCache实现,支持FX和netstandard2.0! 后续例程与使用说明...

12630
来自专栏破晓之歌

python+Django+mysql多图,多文件上传(包含admin)

新建app,修改setting.py中的installed_app和静态路径,增加媒体路径

33520
来自专栏技术博客

Asp.Net Mvc3.0(MEF依赖注入实例)

在http://www.cnblogs.com/aehyok/p/3386650.html前面一节主要是对MEF进行简单的介绍。本节主要来介绍如何在Asp.Ne...

9920
来自专栏菩提树下的杨过

CKEditor/CKFinder升级心得

这几天把一个旧项目中的fckeditor升级为ckeditor 3.2 + ckfinder 1.4.3 组合,下面是一些升级心得: 一、CKFinder的若干...

39370
来自专栏别先生

jsp+servlet实现文件的上传和下载

实现文件的上传和下载首先需要理解几个知识,这样才可以很好的完成文件的上传和下载;   (1):上传文件是上传到服务器上,而保存到数据库是文件名   (2):上传...

368100
来自专栏有趣的django

Django rest framework源码分析(4)----版本

版本  新建一个工程Myproject和一个app名为api (1)api/models.py from django.db import models c...

37860

扫码关注云+社区

领取腾讯云代金券