Skip to content

combinations-wx-pay-starter

1.功能介绍

支持通过一行代码调用以下功能:

  • 预支付:发起微信支付请求,获取支付相关信息。
  • 支付结果回调:处理微信支付结果的回调请求。
  • 查询订单状态:查询微信支付订单的支付状态。
  • 关闭订单:关闭指定的支付订单。

2.配置示例

yaml
sun-rays:
  wx:
    pay:
      merchant-id: ${MERCHANT_ID} # 商户号
      appid: ${APPID} # 应用的appid
      merchant-serial-number: ${MERCHANT_SERIAL_NUMBER} # 商户API证书序列号
      private-key-path: ${PRIVATE_KEY_PATH} # 商户API证书私钥路径
      api-v3-key: ${API_V3_KEY} # 商户APIV3密钥
      cert-file-path: ${CERT_FILE_PATH} # 微信支付平台的证书路径
      notify-url: ${NOTIFY_URL} # 支付结果回调url(https)

3.案例演示

1.创建模块

CleanShot 2025-01-26 at 16.10.59@2x

2.目录结构

CleanShot 2025-01-26 at 16.18.00@2x

3.pom.xml

xml
<dependencies>
    <!-- combinations-wx-pay-starter -->
    <dependency>
        <groupId>cn.sunxiansheng</groupId>
        <artifactId>combinations-wx-pay-starter</artifactId>
    </dependency>
    <!-- 必须引入 -->
    <dependency>
        <groupId>cn.sunxiansheng</groupId>
        <artifactId>common-log4j2-starter</artifactId>
    </dependency>

    <!-- env模块确保数据安全 -->
    <dependency>
        <groupId>cn.sunxiansheng</groupId>
        <artifactId>common-env-starter</artifactId>
    </dependency>
</dependencies>

4.application.yml 配置日志存储根目录、.env文件的绝对路径以及微信支付

yaml
sun-rays:
  log4j2:
    home: /Users/sunxiansheng/IdeaProjects/sunrays-framework-demo/combinations-wx-pay-starter-demo/logs # 日志存储根目录
  env:
    path: /Users/sunxiansheng/IdeaProjects/sunrays-framework-demo/combinations-wx-pay-starter-demo # .env文件的绝对路径
  wx:
    pay:
      merchant-id: ${MERCHANT_ID} # 商户号
      appid: ${APPID} # 应用的appid
      merchant-serial-number: ${MERCHANT_SERIAL_NUMBER} # 商户API证书序列号
      private-key-path: ${PRIVATE_KEY_PATH} # 商户API证书私钥路径
      api-v3-key: ${API_V3_KEY} # 商户APIV3密钥
      cert-file-path: ${CERT_FILE_PATH} # 微信支付平台的证书路径
      notify-url: ${NOTIFY_URL} # 支付结果回调url(https)

5..env

properties
MERCHANT_ID=商户号
APPID=应用的appid
MERCHANT_SERIAL_NUMBER=商户API证书序列号
PRIVATE_KEY_PATH=商户API证书私钥路径
API_V3_KEY=商户APIV3密钥
CERT_FILE_PATH=微信支付平台的证书路径
NOTIFY_URL=支付结果回调url(https)

6.WxPayController.java 微信支付的Controller

java
package cn.sunxiansheng.wx.pay.controller;

import cn.sunxiansheng.log4j2.annotation.SkipLogAspect;
import cn.sunxiansheng.tool.utils.JsonUtil;
import cn.sunxiansheng.wx.pay.config.entity.WxPayPrePayEntity;
import cn.sunxiansheng.wx.pay.config.service.WxPayService;
import cn.sunxiansheng.wx.pay.config.utils.WxPayUtil;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * Description: WxPayController
 *
 * @Author sun
 * @Create 2025/1/24 14:25
 * @Version 1.0
 */
@RestController
@RequestMapping("/wx/pay")
@Slf4j
public class WxPayController {

    /**
     * 注入框架封装好的WxPayService
     */
    @Resource
    private WxPayService wxPayService;

    /**
     * A test endpoint.
     *
     * @return A sample response.
     */
    @RequestMapping("/test")
    public String test() {
        return "This is a test response from WxPayController";
    }

    /**
     * 生成订单号
     *
     * @return
     */
    private String generateOutTradeNo() {
        // 当前时间,格式为yyyyMMddHHmmssSSS
        String timestamp = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
        // 生成3位随机数
        int random = new Random().nextInt(900) + 100;
        // 拼接订单号
        return "ORD" + timestamp + random;
    }

    @Data
    public static class PrepayReq {
        /**
         * 商品金额
         */
        private Double mount;
        /**
         * 商品名称
         */
        private String name;
    }

    @Data
    public static class PrepayVo {
        /**
         * 二维码的url
         */
        private String codeUrl;
        /**
         * 全局唯一订单号
         */
        private String outTradeNo;
        /**
         * 过期时间
         */
        private String timeExpire;
    }

    /**
     * 前端携带用户购买商品信息向后端发送下单请求,Native支付预下单
     *
     * @param prepayReq 商品金额
     * @return 返回code_url,也就是二维码链接
     */
    @RequestMapping("/prepay")
    public PrepayVo prepay(@RequestBody PrepayReq prepayReq) {
        // 唯一订单号
        String outTradeNo = generateOutTradeNo();
        // 选填:用户能够完成该笔订单支付的最后时限(两分钟)
        String timeExpire = WxPayUtil.getTimeExpire(2, TimeUnit.MINUTES);

        // 一行调用接口
        PrepayResponse prepay = wxPayService.prepay(
                new WxPayPrePayEntity("自定义的商品描述",
                        outTradeNo,
                        (int) (prepayReq.getMount() * 100))
                        .setTimeExpire(timeExpire));

        // 封装Vo
        PrepayVo prepayVo = new PrepayVo();
        prepayVo.setCodeUrl(prepay.getCodeUrl());
        prepayVo.setOutTradeNo(outTradeNo);
        prepayVo.setTimeExpire(timeExpire);
        return prepayVo;
    }

    @SkipLogAspect // 跳过日志切面的处理,因为有大对象
    @PostMapping("/callback")
    public ResponseEntity<String> callback(
            HttpServletRequest request
    ) {
        return wxPayService.callback(request, (transaction) -> {
            String prettyJson = JsonUtil.toPrettyJson(transaction);
            // 对解密后的业务逻辑进行处理(一锁、二判、三更新),成功返回true,失败返回false
            log.info("对解密后的业务逻辑进行处理:{}", prettyJson);
            return true;
        });
    }

    /**
     * 商户订单号查询订单状态
     */
    @RequestMapping("/queryOrderByOutTradeNo")
    public Transaction queryOrderByOutTradeNo(@RequestParam String outTradeNo) {
        return wxPayService.queryOrderByOutTradeNo(outTradeNo);
    }

    /**
     * 根据商户订单号关闭订单
     */
    @RequestMapping("/closeOrder")
    public void closeOrder(@RequestParam String outTradeNo) {
        wxPayService.closeOrder(outTradeNo);
    }
}

7.WxPayApplication.java 启动类

java
package cn.sunxiansheng.wx.pay;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Description: WxPayApplication
 *
 * @Author sun
 * @Create 2025/1/24 14:22
 * @Version 1.0
 */
@SpringBootApplication
public class WxPayApplication {

    public static void main(String[] args) {
        SpringApplication.run(WxPayApplication.class, args);
    }
}