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项目中完成微信支付的对接。具体实现需参考微信支付官方文档调整参数和接口调用方式。

相关推荐
AlienZHOU1 小时前
AI Coding 时代下,我的技术面试实践分享
前端·后端·面试
狗头大军之江苏分军3 小时前
《潮水漫过十七岁》开学了
后端
苏三说技术4 小时前
如何看待GPT-6在UP主众测中碾压夺冠?它是现在最强大模型吗?
后端
mldong4 小时前
一份 JSON,一条能跑的审批流:把报销流程送上工作流引擎
后端·架构
wno7044 小时前
Spring Boot WebFlux增删改查
java·spring boot·后端
Captaincc4 小时前
AI用量v0.1.11更新发布 新增 jusage doctor 诊断指令 托盘展示token 和余额 新增 AutoClaw 支持
前端·后端·vibecoding
aramae5 小时前
模拟实现strlen()函数 (C语言)
c语言·开发语言·后端
IT_陈寒6 小时前
Python的GIL把我坑惨了,多线程跑得比单线程还慢
前端·人工智能·后端
分支预测失败6 小时前
RISC-V 时间子系统深度专题:mtime 访问路径、SBI 定时器与 Linux tickless 协同
后端
65岁退休Coder6 小时前
PI Agent 开发一个生产级 Harness
后端·node.js·agent