目录
前段时间,开发了一个微信小程序项目,里面涉及到微信支付,在此整理记录一下:
小程序支付官方文档
前提条件:申请微信小程序,进行企业认证,认证通过后,需要接入微信支付。
一、前期准备工作
1.申请小程序开发者账号并认证
申请小程序开发者账号,进行微信认证,获取appid登录mp.weixin.qq.com,注册一个小程序的开发者账号。
申请指引:https://mp.weixin.qq.com/debug/wxadoc/introduction/index.html
获取到小程序开发者账号后,进行微信认证。
微信认证指引:https://mp.weixin.qq.com/debug/wxadoc/introduction/#
小程序申请微信认证:
- 微信认证入口:登录小程序-设置-微信认证详情
2.小程序开通微信支付
小程序开通微信支付,即申请或复用微信支付商户号 申请完小程序后,登录小程序后台(mp.weixin.qq.com)。点击左侧导航栏的微信支付,在页面中进行开通。(开通申请要求小程序已发布上线)
点击开通按钮后,有2种方式可以获取微信支付能力,新申请微信支付商户号或绑定一个已有的微信支付商户号,请根据你的业务需要和具体情况选择,只能二选一。
3.开发指引
除被扫支付场景以外,商户系统先调用统一下单接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易会话标识后再按扫码、JSAPI、APP、小程序等不同场景生成交易串调起支付,具体API接口请查看"API列表"
注意:
- appid必须为最后拉起收银台的小程序appid;
- mch_id为和appid成对绑定的支付商户号,收款资金会进入该商户号;
- trade_type请填写JSAPI;
- openid为appid对应的用户标识,即使用wx.login接口获得的openid
A.小程序支付的交互图
B.商户系统和微信支付系统主要交互:
①小程序内调用登录接口,获取到用户的openid,api参见公共api【小程序登录API】
②商户server调用支付统一下单,api参见公共api【统一下单API】
③商户server调用再次签名,api参见公共api【再次签名】
④商户server接收支付通知,api参见公共api【支付结果通知API】
⑤商户server查询支付结果,如未收到支付通知的情况,商户后台系统可调用【查询订单API】 (查单实现可参考:支付回调和查单实现指引)
4.到官方下载Java的支付SDK
下载地址:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=11_1#
下载后进行解压,可以看到sdk下的文件,下图:
用于参考。
二、代码实现
1.开发流程:
1.进入小程序,进行下单,生成待支付商品订单信息,生成成功返回商品订单编号;
2.在小程序端(上一步的回调函数中)调用后台微信统一下单接口,组装必要的参数(商品订单编号、openid),调用小程序API:https://api.mch.weixin.qq.com/pay/unifiedorder,调用成功返回预付单信息prepay_id、appId、timeStamp、nonceStr、paySign等
3.上一步的回调函数中,使用wx.requestPayment方法发起支付,支付成功后,后台会进入配置的回调接口,进行相关逻辑处理。
4.支付回调:回调中会返回业务结果、进行签名校验;校验成功,进行自己的逻辑处理,如订单状态修改、减库存等。
2.实现步骤
创建Springboot项目,添加微信支付sdk相关依赖:
<!--web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--微信支付 -->
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-miniapp</artifactId>
<version>3.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.binarywang/weixin-java-pay -->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-pay</artifactId>
<version>3.7.8.B</version>
</dependency>
2.1 下单,生成待支付订单
controller:
@RestController
@RequestMapping("/anon/course")
public class WxCourseController {
/**
* 生成确认订单信息
* @param request
* @param cartIds 购物车ids
* @param third_session 登录用户唯一凭证
* @return
* @throws Exception
*/
@RequestMapping(value="addConfirmOrderInfo",method = RequestMethod.POST)
public Map<String, Object> addConfirmOrderInfo(HttpServletRequest request) throws Exception{
synchronized (WxCourseService.class) {
return wxCourseService.addConfirmOrderInfo(request);
}
}
}
serviceImpl:
/**
* 生成确认订单信息
*/
@Override
public Map<String, Object> addConfirmOrderInfo(HttpServletRequest request) throws Exception {
Map<String, Object> result = new HashMap<String, Object>();
//把请求参数转为map
Map<String, Object> paramMap=GetParamToMap.getParameterMapWXCode(request,redisUtil);
String cartIds = String.valueOf(paramMap.get("cartIds"));
String s[]=cartIds.split(",");
//根据cartIds获取购物车列表信息
List<Map<String,Object>> cartList=courseMapper.getConfirmOrderByCartIds(cartIds.split(","));
List<Map<String,Object>> detaillist = new ArrayList<Map<String,Object>>();
String order_number=OrderNoUtil.getOrderNumber();//订单编号
for(Map<String,Object> data:cartList){
//根据课程id获取课程信息
Map<String,Object> productInfo=courseMapper.getCourseInfoById(data);
if(productInfo == null){
result.put(ErrorCode.MSG, "订单中有课程已不存在");
result.put(ErrorCode.STATE, ErrorCode.FAIl);
return result;
}else{
String status= String.valueOf(productInfo.get("status"));//1:已发布 2:已下架
String del_flag= String.valueOf(productInfo.get("del_flag"));//删除标志(0代表存在 1代表删除)
if(status.equals("2")){
result.put(ErrorCode.MSG, "订单中有课程已下架");
result.put(ErrorCode.STATE, ErrorCode.FAIl);
return result;
}
if(del_flag.equals("1")){
result.put(ErrorCode.MSG, "订单中有课程已删除");
result.put(ErrorCode.STATE, ErrorCode.FAIl);
return result;
}
//组装订单详情信息
data.put("order_number", order_number);
detaillist.add(data);
}
}
//根据cartIds获取购物总金额
double totalMoney = courseMapper.getTotalMoneyByCartIds(cartIds.split(","));
//过期时间15分钟
Date nowDate = new Date();
Date afterDate = new Date(nowDate.getTime()+300000*3);
//生成订单信息
Map<String, Object> orderDataMap = new HashedMap<String, Object>();
orderDataMap.put("order_number", order_number);//订单编号
orderDataMap.put("order_money", totalMoney);//订单金额
orderDataMap.put("order_status", 1);//订单状态 1待付款 2已付款 3已取消 4免费课程
orderDataMap.put("openid", paramMap.get("openid"));//下单用户openid
orderDataMap.put("wx_user_id", paramMap.get("MY_USERID"));//下单用户id
orderDataMap.put("paymoney", totalMoney);//实际支付金额
orderDataMap.put("remark", paramMap.get("remark"));//订单备注
orderDataMap.put("end_time", afterDate);//支付结束时间
Integer n = courseMapper.addConfirmOrderInfo(orderDataMap);
if(n>0){
//添加课程订单详情信息
courseMapper.addOrderDetail(detaillist);
//删除购物车
for(Map<String,Object> data:cartList){
courseMapper.delCourseShoppingCart(data);
}
result.put(ErrorCode.DATA, order_number);
result.put(ErrorCode.STATE, ErrorCode.SUCCESS);
}else{
result.put(ErrorCode.MSG, "操作失败");
result.put(ErrorCode.STATE, ErrorCode.FAIl);
}
return result;
}
小程序端:
- 下单方法:
//添加课程订单(微信统一下单接口)
addConfirmOrderInfo(){
var that = this;
//购物车ids
var cartIds = this.data.cartIds
//订单备注
var remark = this.data.remark
var obj={
cartIds: cartIds,
remark:remark
}
api.addConfirmOrderInfo(obj).then(res =>{
console.log('res',res)
if(res.returnCode == 200){
//成功
obj.order_number=res.data
//调用微信统一下单
that.wxUnifiedorder(obj)
}
})
},
- api接口:
//业务api
import fly from './request.js'
const baseURL = 'http://192.168.43.142:8100'
//生成确认订单
addConfirmOrderInfo:(data) => fly.post('/anon/course/addConfirmOrderInfo',data,{
baseURL: baseURL
}),
2.2 调用微信统一下单
controller:
/**
* 微信统一下单接口
* @return
* @throws Exception
*/
@RequestMapping(value="wxUnifiedorder",method = RequestMethod.POST)
public Map<String, Object> getPrePayInfo(HttpServletRequest request) throws Exception {
synchronized (WxCourseService.class) {
return wxCourseService.getPrePayInfo(request);