Spring Boot 集成微信支付全流程教程
基于Spring Boot开发的项目如何接入微信支付功能?下面详细介绍如何在Spring Boot项目里完成微信支付的对接。
一、前期准备工作
(一)注册微信支付商户账号
首先,要前往微信支付商户平台进行注册,注册完成后需完成实名认证。这一步完成后,会获取到几个关键信息:
appid
:这是公众号或小程序的唯一标识AppID,在后续的支付流程中用于识别应用身份。mch_id
:即微信支付商户号,用于标识商户身份,是与微信支付交互的重要身份凭证。api_key
:这是在商户平台自行设置的API密钥,主要用于对支付请求进行签名,保障数据的安全性和完整性。notify_url
:支付结果回调地址,微信支付会将支付结果发送到这个地址,务必保证该地址能在公网上被访问到。
(二)配置开发环境
项目开发环境也有一定要求。一方面,要确保项目使用的是Java 8及以上版本,并且基于Spring Boot 2.x进行开发。另一方面,由于微信支付规定回调地址必须使用HTTPS,所以还需要配置好域名并开启HTTPS服务。
二、添加项目依赖
在Spring Boot项目的pom.xml
文件中,添加一些必要的依赖,这些依赖会在后续的开发过程中发挥重要作用:
<!-- HTTP客户端,用于发起HTTP请求与微信支付服务器交互 --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency> <!-- XML处理,因为微信支付的请求和响应数据大多是XML格式,这个依赖用于处理XML数据 --> <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency> <!-- 其他Spring Boot基础依赖,用于构建Web应用,提供基础的Web功能支持 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
三、配置微信支付参数
(一)在配置文件中设置参数
在application.yml
文件里配置微信支付相关参数:
wxpay: appid: your_appid mch-id: your_mch_id api-key: your_api_key notify-url: https://your-domain.com/pay/notify
这里需要把your_appid
、your_mch_id
、your_api_key
和https://your-domain.com/pay/notify
替换成实际获取到的AppID、商户号、API密钥以及支付结果回调地址。
(二)读取配置参数
通过@ConfigurationProperties
注解读取配置文件中的参数:
@Configuration @ConfigurationProperties(prefix = "wxpay") @Data public class WxPayConfig { private String appid; private String mchId; private String apiKey; private String notifyUrl; }
这段代码定义了一个配置类WxPayConfig
,它会读取application.yml
中wxpay
前缀下的参数,并将其注入到对应的属性中。
四、实现工具类
(一)签名工具类
签名在支付过程中用于验证数据的完整性和真实性,下面是签名工具类的实现:
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(); } }
在这个工具类中,generateSign
方法首先对传入的参数进行排序,然后拼接成特定格式的字符串,最后使用MD5算法进行签名(也可以选择HMAC – SHA256算法)。
(二)HTTP请求工具类
为了方便与微信支付服务器进行通信,还需要一个HTTP请求工具类:
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"); } }
这个类的post
方法使用HttpClients
创建一个默认的HTTP客户端,然后构建一个POST请求,将XML格式的数据发送到指定的URL,并返回服务器的响应数据。
五、实现统一下单接口
在Controller中创建统一下单的接口:
@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"); } }
在这个接口中,首先构建支付请求参数,然后生成签名并添加到参数中,接着将参数转换为XML格式,调用微信统一下单接口,最后解析返回的XML数据,获取支付二维码链接(code_url
)或预支付交易会话标识(prepay_id
)。
六、处理支付回调
支付完成后,微信会向回调地址发送支付结果通知,下面是回调接口的实现:
@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>"; }
在这个回调接口中,首先读取微信发送的回调数据,然后验证签名的正确性。如果签名验证通过,就可以根据业务需求处理订单状态更新等逻辑,最后返回成功响应给微信。
七、其他支付相关功能
(一)订单查询
要查询订单状态,可以调用https://api.mch.weixin.qq.com/pay/orderquery
接口,在请求时传递订单号等必要参数,就能获取订单的当前状态信息。
(二)退款操作
退款功能需要调用https://api.mch.weixin.qq.com/secapi/pay/refund
接口,并且在调用时需要使用商户证书(.p12
文件),以确保退款操作的安全性。
八、对接过程中的注意事项
(一)金额单位
微信支付的金额单位是分,在设置订单金额时,要注意将以元为单位的金额转换为分。例如,1元在微信支付中应表示为100分。
(二)超时处理
在与微信支付服务器交互过程中,可能会遇到网络问题导致请求超时。因此,需要设置合理的超时时间,并建立重试机制,以确保支付流程的稳定性。
(三)幂等性处理
支付回调可能会因为网络等原因出现重复通知的情况,在处理回调时要确保业务操作的幂等性,避免重复处理导致数据不一致等问题。
(四)日志记录
在整个支付对接过程中,记录关键步骤的日志非常重要。这些日志可以帮助快速定位和排查问题,提高开发和调试效率。
(五)沙箱测试
在正式上线前,一定要使用微信支付沙箱环境进行测试。通过沙箱测试,可以在模拟的真实环境中验证支付功能是否正常,减少上线后的风险。
通过以上步骤,就可以在Spring Boot项目中完成微信支付的对接。不过,具体实现过程中可能需要根据微信支付官方文档,对参数和接口调用方式进行适当调整。