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

相关推荐
llz_11243 分钟前
web-第二次课后作业
前端·后端·web
红尘散仙7 小时前
我把终端小说阅读器接上了 AI Agent:TRNovel 现在能用 skill 生成书源了
人工智能·后端·rust
卷毛的技术笔记8 小时前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
会编程的土豆8 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
喵个咪9 小时前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
basketball6169 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang
qq_2518364579 小时前
SpringBoot+Vue 共享电池柜管理系统 完整实现 前后端分离项目实战 完整代码
vue.js·spring boot·后端
zhangxingchao10 小时前
AI 大模型核心六:量化、Workflow 与 Agent、多轮 RAG
前端·人工智能·后端
IT_陈寒11 小时前
Vite打包时遇到的坑,原来问题出在这里
前端·人工智能·后端
ayqy贾杰12 小时前
基层管理的三板斧,在AI时代行不通了
前端·后端·团队管理