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

相关推荐
景天科技苑1 小时前
【Rust泛型】Rust泛型使用详解与应用场景
开发语言·后端·rust·泛型·rust泛型
lgily-12253 小时前
常用的设计模式详解
java·后端·python·设计模式
意倾城4 小时前
Spring Boot 配置文件敏感信息加密:Jasypt 实战
java·spring boot·后端
火皇4054 小时前
Spring Boot 使用 OSHI 实现系统运行状态监控接口
java·spring boot·后端
薯条不要番茄酱5 小时前
【SpringBoot】从零开始全面解析Spring MVC (一)
java·spring boot·后端
懵逼的小黑子12 小时前
Django 项目的 models 目录中,__init__.py 文件的作用
后端·python·django
小林学习编程13 小时前
SpringBoot校园失物招领信息平台
java·spring boot·后端
java1234_小锋15 小时前
Spring Bean有哪几种配置方式?
java·后端·spring
柯南二号16 小时前
【后端】SpringBoot用CORS解决无法跨域访问的问题
java·spring boot·后端
每天一个秃顶小技巧17 小时前
02.Golang 切片(slice)源码分析(一、定义与基础操作实现)
开发语言·后端·python·golang