前言

微信支付是企业级项目中经常使用到的功能,作为后端开发人员,完整地掌握该技术是十分有必要的。

logo

一、申请流程和步骤

图1-1

  • 注册微信支付账号

  • 获取微信小程序APPID

  • 获取微信商家的商户ID

  • 获取微信商家的API私钥

  • 配置微信支付回调地址

  • 绑定微信小程序和微信支付的关系

  • 搭建SpringBoot工程编写后台支付接口

  • 发布部署接口服务项目

  • 使用微信小程序或者UniAPP调用微信支付功能

  • 支付接口的封装

  • 配置jwt或者openid的token派发

  • 原生微信小程序完成支付对接


二、注册商家

2.1商户平台

商家或者企业想要通过微信支付来进行商品的销售,必须先通过微信平台(pay.weixin.qq.com)去将商家进行注册。注册成功后将会有商户信息等界面,包括商家的账户信息、企业信息等等。如图2-1所示:

图2-1

2.2商户id

商户id是项目开发中的唯一标识,是微信支付给予每个商户或者企业的唯一id。也是客户(消费者)在拉起微信支付时的凭据之一,在图2-1中的“微信支付商户号”就是商户id。


三、API私钥(支付密钥)

在注册商户成功后,同样在微信平台(pay.weixin.qq.com)可以对API私钥进行设置。如图3-1所示:

图3-1

API私钥也称为支付密钥,商户id和API密钥是用户拉起微信支付时后台所必须获取的。


四、商户签约微信支付产品

商户可以根据需要签约微信支付的产品,主要包括有:

  1. JSAPI支付:商户通过调用微信支付提供的JSAPI接口,在支付场景中调起微信支付模块完成收款;
  2. Native支付:商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模式;
  3. 小程序支付:通过好友分享或扫描二维码在微信内打开小程序时,可以调用微信支付完成下单购买的流程;
  4. 付款码支付:用户出示微信钱包中的条码、二维码,商家通过扫描用户条码即可完成收款;
  5. 刷脸支付:用户在集成微信刷脸支付SDK的线下机具上"刷脸"即可完成支付。

如图4-1所示:

图4-1


五、配置回调地址

支付回调地址是微信支付服务器返回给用户支付信息(通知)的地址。如果商户签约的是微信小程序产品,那么支付回调地址可以配置也可以不进行配置。该地址为公司的域名,或者不加以配置。


六、小程序获取APPID

首先要登录申请官网进行微信小程序的注册:https://mp.weixin.qq.com/,如图6-1所示:

图6-1

注册成功后即可获得小程序唯一的APPID。如图6-2所示:

图6-2

七、微信支付与小程序绑定

在微信支付平台对APPID进行绑定即可。如图7-1所示:

图7-1


八、实战部分


8.1SpringBoot框架搭建

  • 首先创建一个初始化SpringBoot项目;

  • 在项目/模块的resources文件夹下,编写properties/yml配置文件;

    • 配置文件中需隔离dev环境与prod环境;
    • 配置文件中还包括了server、数据库、spring、token、日志、时区、json格式、mybatis-plus、swagger、redis、服务器配置、微信小程序配置(包括支付相关)等等全局统一配置。
  • 项目基本架构(SSM:Spring+SpringMVC+MyBatis)

    • controller

      • 后端接口,与前端数据交互
    • config
      • 云服务器配置
      • Swagger配置
      • 接口拦截器(路由)
      • 微信支付配置(引入微信相关服务)
    • common
      • constant
      • enums
      • Ajaxresult
      • BaseController
      • BaseEntity
      • Page(Page与Table返回参数)
    • domain
      • 接口与页面所需参数(DTO、entity、req、res、VO等)
    • mapper
      • mapper文件接口(SQL方法定义)
    • service
      • Service:承接Controller层的接口方法定义
      • Impl(接口实现类):接口的具体实现逻辑
    • utils
      • 文件工具类
      • Json工具类
      • 时间格式工具类
      • 第三方登录工具类

8.2微信支付相关接口

8.2.1小程序用户登录接口

用户首先需要在小程序端进行微信用户登录授权,需调用接口获取登录凭证(code)。通过凭证进而换取用户登录态信息,包括用户在当前小程序的唯一标识(openid)、微信开放平台帐号下的唯一标识(unionid,若当前小程序已绑定到微信开放平台帐号)及本次登录的会话密钥(session_key)等。

具体的登录流程如图8-1所示:

图8-1

此时调用服务端接口,请求参数如图8-2所示:

图8-2

用户登录后的返回参数,如图8-3所示:

图8-3

8.2.2统一下单接口

用户登录小程序后,在小程序页面拉起支付请求时,会调用统一的下单接口。

在拉起支付请求时,下单接口参数需要两部分:一是商户、小程序相关的openid,appid等,二是需要商品相关的价格,名称,数量等参数。

以下将用代码来对微信支付接口做详细的讲解,代码以REST风格API接口的形式编写。

统一下单接口

@ApiOperation(value = "统一下单接口")
@RequestMapping(value = "/unifiedOrder",method = RequestMethod.POST)
public AjaxResult unifiedOrder(HttpServletRequest req,@RequestBody){
//校验小程序(微信)用户登录
//查询数据库订单信息(状态)
//只有未支付订单才能发起支付
//0元购买不调支付
/**
* 设置商户、小程序相关请求参数
* */
//获取小程序的appId
String appId = WxMaUtil.getAppId(request);
WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
wxPayUnifiedOrderRequest.setAppid(appId);
//商品名称
String body = sysOrdersCourse.getCourseName();
body =body.length() > 40 ? body.substring(0,39) : body;
wxPayUnifiedOrderRequest.setBody(body);
//订单编号
wxPayUnifiedOrderRequest.setOutTradeNo(sysOrders.getOrderNo());
//订单金额
wxPayUnifiedOrderRequest.setTotalFee(sysOrders.getOrderAmount().multiply(new BigDecimal(100)).intValue());
//交易类型
wxPayUnifiedOrderRequest.setTradeType("JSAPI");
//支付回调地址
wxPayUnifiedOrderRequest.setNotifyUrl(env.getProperty("notify-host")+"/wx/api/order/notify-order");
wxPayUnifiedOrderRequest.setSpbillCreateIp("127.0.0.1");
//用户在当前小程序中的唯一标识
wxPayUnifiedOrderRequest.setOpenid(wxUser.getOpenId());
//调用微信服务类
WxPayService wxPayService = WxPayConfiguration.getPayService();
return AjaxResult.success(JSONUtils.parse(wxPayService.createOrder(wxPayUnifiedOrderRequest)));
}
8.2.3创建订单接口

创建订单接口

用户可以在商品页面对某个商品进行下单,此时需要创建该用户购买某个商品的订单。

该过程主要是通过接口去请求用户信息、商品信息等参数,经过逻辑判断(是否存在已购买的订单)后创建(数据库插入相关信息)新的订单,最后返回该订单的所需数据。

@ApiOperation(value = "创建订单")
@RequestMapping(value = "/create",method = RequestMethod.POST)
public AjaxResult create(@RequestBody WxOrderRequest wxOrderRequest){
//微信用户信息
//判断是否购买过相同商品,若已经购买过,则无法创建新的订单
//满足条件后将数据插入数据库
WxOrderResponse wxOrderResponse = orderService.add(wxOrderRequest);
//如果新增失败,则返回提示
if (wxOrderResponse == null){
return AjaxResult.error("订单创建失败");
}
return AjaxResult.success(wxOrderResponse);
}
8.2.4取消订单接口

取消订单接口

当用户拉起微信支付时,如果在付款界面点击×取消付款(但此时订单已经创建),则该操作视为取消订单支付,同时在订单页面应当显示此时该订单的支付状态。

该接口可以通过订单id来作为请求参数,首先判断数据库中是否存在该订单信息,接着对可以取消支付的订单类型进行限制,最后更新数据库表(订单、商品和声明周期)状态。

@ApiOperation(value = "取消订单")
@RequestMapping(value = "/cancel/{orderId}",method = RequestMethod.PUT)
public AjaxResult cancel(@PathVariable Long orderId){
//判断订单是否存在
SysOrders sysOrders = sysOrdersService.getById(orderId);
if(sysOrders==null){
return AjaxResult.error("订单不存在");
}
//只有未支付的订单能取消
if(!CommonConstants.NO.equals(sysOrders.getIsPay())){
return AjaxResult.error(MyReturnCode.ERR_70001.getCode(), MyReturnCode.ERR_70001.getMsg());
}
sysOrdersService.orderCancel(sysOrders);
return AjaxResult.success();
}
8.2.5订单详情接口

订单详情接口

当订单生成后,用户可以在页面查看该商品订单的详情。

该接口通过订单id即可从数据库获取详情信息,而该页面展示的数据由业务需求确定。

@ApiOperation(value = "订单详情")
@RequestMapping(value = "/myOrderDetail/{orderId}",method = RequestMethod.GET)
@ApiImplicitParams({@ApiImplicitParam(name = "orderId", value = "订单Id")})
public AjaxResult myOrderDetail(@PathVariable Long orderId){
//从数据库获取详情参数
SysOrderDetailResponse detailResponse = sysOrdersService.getDetail(orderId);
return AjaxResult.success(detailResponse);
}

订单详情逻辑

    /**
* 订单详情页面参数处理
* @param orderId
* @return sysOrderDetailResponse
*/
@Override
public SysOrderDetailResponse getDetail(Long orderId) {
SysOrderDetailResponse sysOrderDetailResponse = orderMapper.getDetail(orderId);
//对页面的手机号做处理
String phoneNum = sysOrderDetailResponse.getMobile();
sysOrderDetailResponse.setMobile(phoneNum.substring(0,3) + "****" + phoneNum.substring(7,phoneNum.length()));
//根据订单状态不同,显示不同的数据
//计算剩余待支付时间并展示
return sysOrderDetailResponse;
}
8.2.6支付回调接口

微信支付回调是用户在对商品进行支付操作后,将数据发送至微信服务器,微信服务器再将支付的结果返回(通知)给用户和商家的过程。

其中,主要关注的是用户支付-微信回调判断-修改数据库这个过程。

支付回调接口

@ApiOperation("支付回调")
@RequestMapping(value = "notify-order", method = RequestMethod.POST)
public String notifyOrder(@RequestBody String xmlData) throws WxPayException {
log.info("支付回调:" + xmlData);
//微信支付服务
WxPayService wxPayService = WxPayConfiguration.getPayService();
WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlData);
log.info("支付回调解析结果" + notifyResult);
//对创建的订单进行支付
SysOrders sysOrders = orderService.getOne(notifyResult.getOutTradeNo());
if (sysOrders != null) {
if (sysOrders.getOrderAmount().multiply(new BigDecimal(100)).intValue() == notifyResult.getTotalFee()){
String timeEnd = notifyResult.getTimeEnd();
LocalDateTime paymentTime = LocalDateTimeUtils.parse(timeEnd);
//支付时间
sysOrders.setPaymentTime(paymentTime);
sysOrders.setOrderAmount(sysOrders.getOrderAmount());
//微信订单编号
sysOrders.setTransactionId(notifyResult.getTransactionId());
//更新数据库
orderService.notifyOrder(sysOrders);
log.info("支付回调成功通知:" + sysOrders.getOrderNo());
return WxPayNotifyResponse.success("支付成功");
} else {
return WxPayNotifyResponse.fail("付款金额与订单金额不符");
}
} else {
return WxPayNotifyResponse.fail("无此订单");
}
}

其中,notifyOrder方法的作用是在支付成功后在数据库更新订单的状态。

notifyOrder(SysOrders sysOrders)方法

@Override
@Transactional(rollbackFor = Exception.class)
public void notifyOrder(SysOrders sysOrders) {
//只有未支付订单能操作,即is_pay字段为0的订单
if(CommonConstants.NO.equals(sysOrders.getIsPay())) {
//更新订单支付状态
sysOrders.setIsPay(CommonConstants.YES);
sysOrders.setStatus(OrderInfoEnum.STATUS_1.getValue());
sysOrdersMapper.updateById(sysOrders);
//更新商品表状态
//更新订单生命周期表
}
}

至此,Spring Boot中的微信支付全过程已经分享完成。如有不足,望大家指正。

Spring Boot中的微信支付(小程序)的更多相关文章

  1. 微信支付-小程序H5 公众号 Payment SDK

    前言 今天是2020年一天,去年最后一个月开发了订单和支付系统,尤其在支付系统和微信对接的时候遇到了很多坑,这里给大家总结下,以免大家遇到相同的问题还浪费大量时间 微信支付前期准备 微信商户号,需要商 ...

  2. 如何在Spring Boot项目中集成微信支付V3

    Payment Spring Boot 是微信支付V3的Java实现,仅仅依赖Spring内置的一些类库.配置简单方便,可以让开发者快速为Spring Boot应用接入微信支付. 演示例子: paym ...

  3. 微信小程序中实现微信支付

    最近在做微信小程序,今天刚好做到小程序里的微信支付这块,踩过不少坑,特此写个博客记录下,希望能帮到其它人吧. 我总结了一下,小程序中的微信支付和之前其它的公众号里的微信支付有两个区别,第一就是小程序必 ...

  4. Spring Boot2 系列教程(八)Spring Boot 中配置 Https

    https 现在已经越来越普及了,特别是做一些小程序或者公众号开发的时候,https 基本上都是刚需了. 不过一个 https 证书还是挺费钱的,个人开发者可以在各个云服务提供商那里申请一个免费的证书 ...

  5. springboot(十一):Spring boot中mongodb的使用

    mongodb是最早热门非关系数据库的之一,使用也比较普遍,一般会用做离线数据分析来使用,放到内网的居多.由于很多公司使用了云服务,服务器默认都开放了外网地址,导致前一阵子大批 MongoDB 因配置 ...

  6. 在Spring Boot中输出REST资源

    前面我们我们已经看了Spring Boot中的很多知识点了,也见识到Spring Boot带给我们的各种便利了,今天我们来看看针对在Spring Boot中输出REST资源这一需求,Spring Bo ...

  7. 如何优雅地在 Spring Boot 中使用自定义注解,AOP 切面统一打印出入参日志 | 修订版

    欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 资深架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...

  8. spring boot中使用@Async实现异步调用任务

    本篇文章主要介绍了spring boot中使用@Async实现异步调用任务,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 什么是“异步调用”? “异步调用”对应的是“同步 ...

  9. (转)Spring Boot 2 (十):Spring Boot 中的响应式编程和 WebFlux 入门

    http://www.ityouknow.com/springboot/2019/02/12/spring-boot-webflux.html Spring 5.0 中发布了重量级组件 Webflux ...

随机推荐

  1. css3中user-select的用法详解

    css3中user-select的用法详解 user-select属性是css3新增的属性,用于设置用户是否能够选中文本.可用于除替换元素外的所有元素,以下是user-select的主要用法和注意事项 ...

  2. 纯css模拟电子钟

    先看效果 演示地址: https://yueminhu.github.io/di...点击左边拉环切换夜间模式. 用到了伪元素生成数字的小三角`currentColor和color: inherit` ...

  3. Ubuntu之安装Gradle

    简介 Gradle 是以 Groovy 语言为基础,面向Java应用为主,基于DSL(领域特定语言)语法的自动化构建工具. 现在Android Studio用它来编译APK程序. 前提 Ubuntu官 ...

  4. 整合SSM框架环境搭建

    知识要求 MySQL相关操作 Maven操作 Mybatis.Spring.SpringMVC三个框架基本操作 JavaWeb等知识 搭建环境 MySQL 8.0 Mybatis 3.5.2 使用c3 ...

  5. Windbg调试工具命令详解

    .cls -------------------------------清屏 ~ ----------------------------------查看当前程序的所有线程 ~0s --------- ...

  6. for in 语法遍历对象

    1. 语法格式 for (变量 in 对象) { console.log(变量) }   2. 代码实例 // 遍历对象 var obj = { name: 'pink老师', age: 18, se ...

  7. HTML续集

    计算机中PC:电脑 移动端:智能手机/智能电脑 html:超文本标记语言 图片标签<img src=" "> 图片的格式类型都有哪些? jpg,peg,gif(动图) ...

  8. Day 005:PAT练习--1047. 编程团体赛(20)

    编程团体赛的规则为:每个参赛队由若干队员组成:所有队员独立比赛:参赛队的成绩为所有队员的成绩和:成绩最高的队获胜.现给定所有队员的比赛成绩,请你编写程序找出冠军队. 输入格式: 输入第一行给出一个正整 ...

  9. es篇-es基础

    点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人. 文章不定期同步公众号,还有各种一线大厂面试原题.我的学习系列笔记. es基础知识 es和solr一样,都是基于Lucene的全文检索数据库 ...

  10. R2DBC正式孵化成功,利好Spring Webflux

    2022年4月25日,R2DBC社区宣布具有普遍可用性的1.0.0.RELEASE正式发布. R2DBC致力于为反应式编程 API操作关系型数据库带来规范支持,R2DBC不同于我们熟知的JDBC规范, ...