Spring Boot与Vue集成微信Native支付及退款全流程解析

今天早睡
今天早睡
发布时间:2026-10-16 | 2人浏览过
原创

详解Spring Boot后端与Vue前端集成微信Native支付及退款的完整代码实现,包括参数配置、二维码生成、状态轮询及证书退款处理。

1. 准备条件与依赖配置

在Spring Boot项目中实现微信支付,首先需要引入官方提供的SDK或第三方封装库,并配置商户核心信息。

第1步:添加Maven依赖

在项目的 order 模块(或相关业务模块)的 pom.xml 中添加微信SDK依赖。这里使用的是较为常见的第三方封装版本:

<dependency>
    <groupId>com.github.wxpay</groupId>
    <artifactId>wxpay-sdk</artifactId>
    <version>0.0.3</version>
</dependency>

第2步:配置商户敏感信息

在配置文件(如 application.yml 或 properties)中保存微信公众号AppID、商户号(Partner ID)及商户密钥(Partner Key)。这些数据用于后续请求签名和身份验证:

# 关联的公众号appid
weixin.pay.appid=wxXXXXXXX
# 商户号
weixin.pay.partner=XXXXXXXXX
# 商户key
weixin.pay.partnerkey=XXXXXXXXXX

2. 实现Native扫码支付流程

Native支付的核心是后端生成包含商品信息的二维码URL,返回给前端展示,前端通过定时器轮询支付结果。

第3步:后端Service层封装下单逻辑

创建 WeiXinServiceImpl,重点实现 createNative 方法。该方法负责组装微信统一下单所需参数,生成签名,发送HTTP请求获取二维码地址。

  • 目的:获取微信生成的付款码URL。
  • 关键步骤:
  1. 根据订单ID查询订单详情,确保订单存在。
  2. 构建参数Map,包含 appid、mch_id、随机串 nonce_str、商品描述 body、商户订单号 out_trade_no、金额 total_fee(单位:分)、终端IP spbill_create_ip、回调地址 notify_url 及交易类型 NATIVE。
  3. 使用工具类将Map转换为XML格式字符串并进行签名。
  4. 通过HTTP Client发送POST请求到微信统一下单接口 https://api.mch.weixin.qq.com/pay/unifiedorder。
  5. 解析返回的XML响应,提取 code_url。
@Service
public class WeiXinServiceImpl implements WeiXinService {
    @Autowired
    private PaymentInfoService paymentInfoService;
    @Autowired
    private OrderInfoService orderInfoService;

    @Override
    public Map createNative(Long orderId) {
        // 1. 查询订单
        OrderInfo orderInfo = orderInfoService.getById(orderId);
        if (orderInfo == null) {
            throw new OrderException(20001, "订单不存在");
        }

        // 记录支付流水
        paymentInfoService.savePaymentInfo(orderInfo, PaymentTypeEnum.WEIXIN.getStatus());

        try {
            // 2. 封装参数
            Map paramMap = new HashMap();
            paramMap.put("appid", ConstantPropertiesUtils.APPID);
            paramMap.put("mch_id", ConstantPropertiesUtils.PARTNER);
            paramMap.put("nonce_str", WXPayUtil.generateNonceStr());

            String body = "就诊" + orderInfo.getDepname(); // 示例业务描述
            paramMap.put("body", body);
            paramMap.put("out_trade_no", orderInfo.getOutTradeNo());
            
            // 注意:实际生产中金额需从数据库读取,此处为测试金额1分
            paramMap.put("total_fee", "1"); 
            paramMap.put("spbill_create_ip", "127.0.0.1");
            paramMap.put("notify_url", "http://your-notify-url/callback");
            paramMap.put("trade_type", "NATIVE");

            // 3. 发送请求
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
            client.setXmlParam(WXPayUtil.generateSignedXml(paramMap, ConstantPropertiesUtils.PARTNERKEY));
            client.setHttps(true);
            client.post();

            // 4. 解析结果
            String resultXml = client.getContent();
            Map<String, String> resultMap = WXPayUtil.xmlToMap(resultXml);

            // 5. 返回前端所需数据
            Map responseMap = new HashMap();
            responseMap.put("orderId", orderId);
            responseMap.put("totalFee", orderInfo.getAmount());
            responseMap.put("codeUrl", resultMap.get("code_url"));
            return responseMap;
        } catch (Exception e) {
            throw new RuntimeException("生成二维码失败", e);
        }
    }
}

第4步:Controller暴露接口

提供REST接口供前端调用:

@RestController
@RequestMapping("/api/order/weixin")
public class WeixinController {
    @Autowired
    private WeiXinService weixinPayService;

    @GetMapping("/createNative/{orderId}")
    public R createNative(@PathVariable Long orderId) {
        Map map = weixinPayService.createNative(orderId);
        return R.ok().data(map);
    }
}

第5步:前端Vue集成显示二维码

前端需安装 vue-qriously 插件以渲染二维码。

  • 安装:npm install vue-qriously
  • 组件示例:在订单详情页弹出Dialog,接收后端返回的 codeUrl 并渲染。
<!-- 模板部分 -->
<el-dialog :visible.sync="dialogPayVisible">
  <qriously :value="payObj.codeUrl" :size="220"/>
  <p>请使用微信扫一扫扫描二维码支付</p>
</el-dialog>

<!-- JS逻辑 -->
pay() {
  this.dialogPayVisible = true;
  weixinApi.createNative(this.orderId).then(response => {
    this.payObj = response.data;
    if (this.payObj.codeUrl) {
      // 开启定时器轮询支付状态
      this.timer = setInterval(() => {
        this.queryPayStatus(this.orderId);
      }, 3000);
    }
  });
}

3. 支付状态查询与通知处理

由于前端无法实时获取支付结果,通常采用轮询机制。同时后端也需支持主动查询。

第6步:后端实现支付状态查询

调用微信“查询订单”接口 https://api.mch.weixin.qq.com/pay/orderquery。

@Override
public Map queryPayStatus(Long orderId, String paymentType) {
    OrderInfo orderInfo = orderInfoService.getById(orderId);
    if (orderInfo == null) throw new RuntimeException("订单不存在");

    try {
        Map paramMap = new HashMap();
        paramMap.put("appid", ConstantPropertiesUtils.APPID);
        paramMap.put("mch_id", ConstantPropertiesUtils.PARTNER);
        paramMap.put("out_trade_no", orderInfo.getOutTradeNo());
        paramMap.put("nonce_str", WXPayUtil.generateNonceStr());

        HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
        client.setXmlParam(WXPayUtil.generateSignedXml(paramMap, ConstantPropertiesUtils.PARTNERKEY));
        client.setHttps(true);
        client.post();

        Map<String, String> resultMap = WXPayUtil.xmlToMap(client.getContent());
        return resultMap;
    } catch (Exception e) {
        throw new RuntimeException("查询失败", e);
    }
}

第7步:前端轮询与状态更新

前端每3秒调用一次查询接口。若后端返回 trade_state 为 SUCCESS,则停止轮询,提示用户支付成功,并关闭弹窗。

4. 实现微信退款功能

退款接口与支付不同,涉及资金回退,因此需要双向SSL证书认证,安全性要求更高。

第8步:配置退款证书

下载微信支付平台证书的 .p12 文件,并在配置文件中指定其本地路径:

weixin.cert=C:\\apiclient_cert.p12

第9步:后端Service层封装退款逻辑

退款接口地址为 https://api.mch.weixin.qq.com/secapi/pay/refund。需注意以下几点:

  • 必须开启证书认证:client.setCert(true)。
  • 设置证书密码,通常为商户MCH_ID。
  • 参数中包含原交易ID transaction_id 或商户订单号 out_trade_no,以及退款金额 refund_fee。
@Override
public Boolean refund(Long orderId) {
    // 1. 获取原支付信息
    PaymentInfo paymentInfo = paymentInfoService.getByOrderId(orderId);

    try {
        // 2. 封装退款参数
        Map<String, String> paramMap = new HashMap();
        paramMap.put("appid", ConstantPropertiesUtils.APPID);
        paramMap.put("mch_id", ConstantPropertiesUtils.PARTNER);
        paramMap.put("nonce_str", WXPayUtil.generateNonceStr());
        paramMap.put("transaction_id", paymentInfo.getTradeNo());
        paramMap.put("out_trade_no", paymentInfo.getOutTradeNo());
        paramMap.put("out_refund_no", "tk" + paymentInfo.getOutTradeNo());
        
        // 退款金额和总金额,单位分
        paramMap.put("total_fee", "1");
        paramMap.put("refund_fee", "1");

        // 3. 发起请求
        HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/secapi/pay/refund");
        client.setXmlParam(WXPayUtil.generateSignedXml(paramMap, ConstantPropertiesUtils.PARTNERKEY));
        client.setHttps(true);
        client.setCert(true);
        client.setCertPassword(ConstantPropertiesUtils.PARTNER); // 证书密码即商户号
        client.post();

        // 4. 解析结果
        String xml = client.getContent();
        Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
        
        return "SUCCESS".equals(resultMap.get("result_code"));
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

以上就是Spring Boot整合Vue实现微信扫码支付以及微信退款功能的详细内容,更多关于Spring Boot Vue微信支付的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表