🧑 博主简介:优快云博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,
15年
工作经验,精通Java编程
,高并发设计
,Springboot和微服务
,熟悉Linux
,ESXI虚拟化
以及云原生Docker和K8s
,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。
技术合作请加本人wx(注明来自csdn):foreast_sea
Java对接微信支付全过程详解
引言
在数字化商业蓬勃发展的今天,移动支付已成为连接用户与服务的核心纽带。微信支付凭借其庞大的用户基数和成熟的生态体系,成为企业拓展线上业务不可或缺的支付工具。然而,对于Java开发者而言,如何高效、安全地对接微信支付接口,构建稳定可靠的支付系统,仍面临诸多技术挑战——从复杂的签名验签机制到异步通知的幂等性处理,从证书管理到高并发场景下的性能优化,每一步都需要精准的技术设计与严谨的代码实现。
本文将以系统性、实战性为导向,深入剖析Java对接微信支付的核心流程与关键技术。无论是Native支付、JSAPI支付还是小程序支付,其底层逻辑均围绕预支付订单生成、支付结果异步通知、订单状态主动查询三大核心环节展开。文章不仅提供清晰的代码示例(基于Spring Boot框架与微信支付V3 API),更聚焦于实际开发中的高频痛点:如何通过RSA签名保障通信安全?如何设计幂等回调接口避免重复扣款?如何利用微信平台证书防止伪造请求?这些问题将在文中逐一击破。
此外,本文还将探讨企业级支付系统中的最佳实践,例如使用WechatPay Apache HttpClient简化证书管理、通过分布式锁实现订单状态同步、结合日志监控提升系统可观测性等。无论您是初探支付领域的开发者,还是需优化现有支付架构的技术负责人,均可从中获得从基础配置到高阶优化的完整知识链路,助力构建高可用、高安全的支付服务体系,为业务增长筑牢技术基石。
一、准备工作
-
注册微信商户平台
- 获取商户号(
mchid
)、API密钥(API_KEY
)。 - 下载API证书(
apiclient_cert.pem
和apiclient_key.pem
)。
- 获取商户号(
-
配置支付参数
# application.properties wxpay.mch-id=你的商户号 wxpay.api-key=你的API密钥 wxpay.notify-url=https://你的域名/api/wxpay/notify
二、核心接口实现
1. 生成预支付订单(Native支付)
public class WxPayService {
private String mchId;
private String apiKey;
private String notifyUrl;
// 初始化参数(通过@Value注入或配置文件读取)
/**
* 生成Native支付二维码链接
*/
public String createNativeOrder(String orderId, int amount) throws Exception {
String url = "https://api.mch.weixin.qq.com/v3/pay/transactions/native";
Map<String, Object> params = new HashMap<>();
params.put("mchid", mchId);
params.put("appid", "你的AppID"); // 如果是公众号/小程序支付
params.put("description", "订单描述");
params.put("out_trade_no", orderId);
params.put("notify_url", notifyUrl);
params.put("amount", Map.of("total", amount, "currency", "CNY"));
// 生成签名并发送请求
String body = JSON.toJSONString(params);
String authorization = generateSignature("POST", url, body);
// 使用OkHttp或RestTemplate发送请求
String response = sendPostRequest(url, body, authorization);
return JSON.parseObject(response).getString("code_url");
}
/**
* 生成V3接口的Authorization头
*/
private String generateSignature(String method, String url, String body) {
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
String nonceStr = UUID.randomUUID().toString().replace("-", "");
String message = method + "\n" + url + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n";
String signature = signWithSHA256RSA(message, apiKey); // 使用私钥签名
return "WECHATPAY2-SHA256-RSA2048 "
+ "mchid=\"" + mchId + "\","
+ "nonce_str=\"" + nonceStr + "\","
+ "timestamp=\"" + timestamp + "\","
+ "serial_no=\"你的证书序列号\","
+ "signature=\"" + signature + "\"";
}
}
2. 处理微信支付回调(关键!)
@RestController
@RequestMapping("/api/wxpay")
public class WxPayCallbackController {
@PostMapping("/notify")
public String handleNotify(@RequestBody String requestBody,
@RequestHeader("Wechatpay-Signature") String signature,
@RequestHeader("Wechatpay-Timestamp") String timestamp,
@RequestHeader("Wechatpay-Nonce") String nonce) {
// 1. 验证签名(防止伪造请求)
String message = timestamp + "\n" + nonce + "\n" + requestBody + "\n";
boolean isValid = verifySignature(message, signature, publicKey); // 使用微信平台公钥验证
if (!isValid) {
return "<xml><return_code>FAIL</return_code></xml>";
}
// 2. 解析回调数据
Map<String, String> result = parseXml(requestBody);
String orderId = result.get("out_trade_no");
String transactionId = result.get("transaction_id");
// 3. 幂等性处理:检查订单是否已处理
if (orderService.isOrderPaid(orderId)) {
return "<xml><return_code>SUCCESS</return_code></xml>";
}
// 4. 更新订单状态
orderService.updateOrderToPaid(orderId, transactionId);
// 5. 返回成功响应(必须!否则微信会重试)
return "<xml><return_code>SUCCESS</return_code></xml>";
}
}
3. 查询订单状态
public class WxPayService {
public Map<String, String> queryOrder(String orderId) throws Exception {
String url = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/"
+ orderId + "?mchid=" + mchId;
String authorization = generateSignature("GET", url, "");
String response = sendGetRequest(url, authorization);
return JSON.parseObject(response, Map.class);
}
}
三、关键注意事项
-
签名验证
- 所有回调必须验证签名,防止伪造请求。
- 使用微信提供的平台证书验证。
-
幂等性设计
- 通过数据库唯一索引或Redis锁防止重复处理订单。
-
证书管理
- 推荐使用
WechatPay Apache HttpClient
简化证书处理:<dependency> <groupId>com.github.wechatpay-apiv3</groupId> <artifactId>wechatpay-apache-httpclient</artifactId> <version>0.4.7</version> </dependency>
- 推荐使用
-
日志记录
- 记录所有微信请求和回调,方便排查问题。
四、完整调用示例(Spring Boot)
@RestController
public class PaymentController {
@Autowired
private WxPayService wxPayService;
@GetMapping("/createOrder")
public String createOrder(@RequestParam String orderId, @RequestParam int amount) {
try {
String codeUrl = wxPayService.createNativeOrder(orderId, amount);
return "<img src=\"https://example.com/qr?data=" + codeUrl + "\">";
} catch (Exception e) {
return "支付创建失败: " + e.getMessage();
}
}
}
五、常见问题解决
- 证书加载失败:检查证书路径和格式(必须为PEM格式)。
- 签名错误:使用微信官方验签工具调试。
- 回调未触发:检查
notify_url
是否外网可访问,且返回SUCCESS
。
通过以上步骤,可完成微信支付的核心对接,确保支付流程的可靠性和安全性。