信息发布→ 登录 注册 退出

Spring Boot中的微信支付全过程(小程序)

发布时间:2026-01-11

点击量:
目录
  • 前言
  • 一、申请流程和步骤
  • 二、注册商家
    • 2.1商户平台
    • 2.2商户id
  • 三、API私钥(支付密钥)
    • 四、商户签约微信支付产品
      • 五、配置回调地址
        • 六、小程序获取APPID
          • 七、微信支付与小程序绑定
            • 八、实战部分
              • 8.1SpringBoot框架搭建
              • 8.2微信支付相关接口
                • 8.2.1小程序用户登录接口
                • 8.2.2统一下单接口
                • 8.2.3创建订单接口
                • 8.2.4取消订单接口
                • 8.2.5订单详情接口
                • 8.2.6支付回调接口

            前言

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

            一、申请流程和步骤

            图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密钥是用户拉起微信支付时后台所必须获取的。

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

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

            • JSAPI支付:商户通过调用微信支付提供的JSAPI接口,在支付场景中调起微信支付模块完成收款;
            • Native支付:商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模式;
            • 小程序支付:通过好友分享或扫描二维码在微信内打开小程序时,可以调用微信支付完成下单购买的流程;
            • 付款码支付:用户出示微信钱包中的条码、二维码,商家通过扫描用户条码即可完成收款;
            • 刷脸支付:用户在集成微信刷脸支付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);
                   //更新商品表状态
                   //更新订单生命周期表
                   }
                }
            在线客服
            服务热线

            服务热线

            4008888355

            微信咨询
            二维码
            返回顶部
            ×二维码

            截屏,微信识别二维码

            打开微信

            微信号已复制,请打开微信添加咨询详情!