Spring Boot中对接微信支付的详细步骤

在Spring Boot中对接微信支付的详细步骤如下:


一、前期准备

  1. 注册微信支付商户账号

    • 前往微信支付商户平台注册并完成实名认证。

    • 获取以下关键信息:

      • appid:公众号或小程序的AppID。
      • mch_id:微信支付商户号。
      • api_key:商户平台设置的API密钥(用于签名)。
      • notify_url:支付结果回调地址(需公网可访问)。
  2. 配置开发环境

    • 确保项目使用Java 8+和Spring Boot 2.x。
    • 配置域名和HTTPS(微信支付要求回调地址必须为HTTPS)。

二、添加依赖

pom.xml中添加必要依赖:

xml 复制代码
<!-- HTTP客户端 -->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>

<!-- XML处理 -->
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

<!-- 其他Spring Boot基础依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

三、配置参数

application.yml中配置微信支付参数:

vbnet 复制代码
wxpay:
  appid: your_appid
  mch-id: your_mch_id
  api-key: your_api_key
  notify-url: https://your-domain.com/pay/notify

通过@ConfigurationProperties读取配置:

less 复制代码
@Configuration
@ConfigurationProperties(prefix = "wxpay")
@Data
public class WxPayConfig {
    private String appid;
    private String mchId;
    private String apiKey;
    private String notifyUrl;
}

四、实现工具类

  1. 签名工具
vbnet 复制代码
public class WxPayUtil {
    public static String generateSign(Map<String, String> data, String apiKey) {
        // 按参数名ASCII字典序排序
        List<String> keyList = new ArrayList<>(data.keySet());
        Collections.sort(keyList);

        StringBuilder sb = new StringBuilder();
        for (String key : keyList) {
            if (!key.equals("sign") && data.get(key) != null && !data.get(key).isEmpty()) {
                sb.append(key).append("=").append(data.get(key)).append("&");
            }
        }
        sb.append("key=").append(apiKey);
        // MD5签名(或使用HMAC-SHA256)
        return DigestUtils.md5Hex(sb.toString()).toUpperCase();
    }
}
  1. HTTP请求工具
java 复制代码
public class WxPayHttpClient {
    public static String post(String url, String xmlData) throws IOException {
        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost post = new HttpPost(url);
        post.setEntity(new StringEntity(xmlData, "UTF-8"));
        post.setHeader("Content-Type", "application/xml");

        CloseableHttpResponse response = client.execute(post);
        return EntityUtils.toString(response.getEntity(), "UTF-8");
    }
}

五、统一下单接口

  1. Controller入口
less 复制代码
@RestController
@RequestMapping("/pay")
public class WxPayController {
    @Autowired
    private WxPayConfig wxPayConfig;

    @PostMapping("/create")
    public String createOrder(@RequestBody OrderRequest orderRequest) throws Exception {
        Map<String, String> data = new HashMap<>();
        data.put("appid", wxPayConfig.getAppid());
        data.put("mch_id", wxPayConfig.getMchId());
        data.put("nonce_str", UUID.randomUUID().toString().replace("-", ""));
        data.put("body", orderRequest.getBody());
        data.put("out_trade_no", orderRequest.getOrderNo());
        data.put("total_fee", String.valueOf(orderRequest.getTotalFee())); // 单位:分
        data.put("spbill_create_ip", "123.12.12.123");
        data.put("notify_url", wxPayConfig.getNotifyUrl());
        data.put("trade_type", "NATIVE"); // JSAPI、APP等

        // 生成签名
        String sign = WxPayUtil.generateSign(data, wxPayConfig.getApiKey());
        data.put("sign", sign);

        // 转换为XML
        String xmlData = mapToXml(data);

        // 调用微信统一下单接口
        String response = WxPayHttpClient.post("https://api.mch.weixin.qq.com/pay/unifiedorder", xmlData);

        // 解析返回的XML,获取code_url或prepay_id
        Map<String, String> respData = parseXml(response);
        return respData.get("code_url");
    }
}

六、处理支付回调

  1. 回调接口实现
xml 复制代码
@PostMapping("/notify")
public String payNotify(HttpServletRequest request) throws Exception {
    // 读取回调数据
    String xmlData = IOUtils.toString(request.getInputStream(), "UTF-8");
    Map<String, String> notifyData = parseXml(xmlData);

    // 验证签名
    String sign = notifyData.get("sign");
    String localSign = WxPayUtil.generateSign(notifyData, wxPayConfig.getApiKey());
    if (!sign.equals(localSign)) {
        return "<xml><return_code><![CDATA[FAIL]]></return_code></xml>";
    }

    // 处理业务逻辑(如更新订单状态)
    String orderNo = notifyData.get("out_trade_no");
    orderService.updateOrderPaid(orderNo);

    // 返回成功响应
    return "<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>";
}

七、其他功能

  1. 订单查询

    • 调用https://api.mch.weixin.qq.com/pay/orderquery接口,传递订单号查询状态。
  2. 退款

    • 调用https://api.mch.weixin.qq.com/secapi/pay/refund接口,需使用商户证书(.p12文件)。

八、注意事项

  1. 金额单位:微信支付以分为单位(如100表示1元)。
  2. 超时处理:设置合理的超时时间和重试机制。
  3. 幂等性:处理回调时确保重复通知不会导致重复业务操作。
  4. 日志记录:记录关键步骤日志,便于排查问题。
  5. 沙箱测试 :使用微信支付沙箱环境进行测试。

通过以上步骤,即可在Spring Boot项目中完成微信支付的对接。具体实现需参考微信支付官方文档调整参数和接口调用方式。

相关推荐
bearpping38 分钟前
SpringBoot最佳实践之 - 使用AOP记录操作日志
java·spring boot·后端
一叶飘零_sweeeet40 分钟前
线上故障零扩散:全链路监控、智能告警与应急响应 SOP 完整落地指南
java·后端·spring
开心就好20252 小时前
不同阶段的 iOS 应用混淆工具怎么组合使用,源码混淆、IPA混淆
后端·ios
架构师沉默2 小时前
程序员如何避免猝死?
java·后端·架构
椰奶燕麦2 小时前
Windows PackageManager (winget) 核心故障排错与通用修复指南
后端
zjjsctcdl3 小时前
springBoot发布https服务及调用
spring boot·后端·https
zdl6863 小时前
Spring Boot文件上传
java·spring boot·后端
世界哪有真情3 小时前
哇!绝了!原来这么简单!我的 Java 项目代码终于被 “拯救” 了!
java·后端
RMB Player3 小时前
Spring Boot 集成飞书推送超详细教程:文本消息、签名校验、封装工具类一篇搞定
java·网络·spring boot·后端·spring·飞书
重庆小透明3 小时前
【搞定面试之mysql】第三篇 mysql的锁
java·后端·mysql·面试·职场和发展