Spring Boot 对接微信支付 V3 版本主要涉及环境准备、核心配置、支付与退款接口实现、以及回调处理等关键步骤。下面是一个清晰的流程指南。
🚀 Spring Boot 对接微信支付V3详细步骤
下面表格汇总了对接微信支付V3的主要阶段和核心任务,帮助您快速把握整体流程。
| 阶段 | 核心任务 | 关键配置/操作 |
|---|---|---|
| 1. 环境准备 | 获取商户信息、配置API密钥、安装证书 | 商户号(mchId)、APIv3密钥、商户证书序列号 |
| 2. 项目配置 | 添加SDK依赖、配置支付参数、初始化支付客户端 | pom.xml依赖、application.yml配置、WechatPayConfig配置类 |
| 3. 支付功能 | 实现统一下单、生成支付签名、处理支付回调 | 调用JSAPI/Native接口、签名生成、回调验签解密 |
| 4. 退款功能 | 实现退款申请、处理退款回调 | 调用退款接口、退款结果异步通知 |
| 5. 安全处理 | 签名验证、敏感信息加密解密 | 验证微信签名、处理加密回调数据 |
1. 环境准备与配置
1.1 获取商户平台关键信息
在开始编码前,您需要从微信商户平台获取以下关键信息:
- 商户号(mchId):微信支付分配的商户标识
- APPID:公众账号ID或应用APPID
- APIv3密钥:用于加密解密和签名验证的32位密钥
- 商户证书序列号:从商户平台下载的API证书序列号
- 商户私钥:从商户平台下载的私钥文件内容
1.2 添加SDK依赖
在pom.xml中添加微信支付Java SDK依赖(根据实际情况选择最新版本):
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
<version>0.4.12</version>
</dependency>
或者使用Apache HttpClient版本的SDK:
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
<version>0.4.8</version>
</dependency>
1.3 配置支付参数
在application.yml/application.properties中配置支付参数:
# application.yml配置示例
wechat:
pay:
appid: your_appid
mchid: your_mch_id
api-v3-key: your_api_v3_key
private-key-path: classpath:apiclient_key.pem
certificate-path: classpath:apiclient_cert.pem
notify-url: your_notify_url
2. 支付客户端配置
2.1 初始化支付客户端
创建配置类初始化微信支付客户端,这是与微信支付API交互的基础:
@Configuration
public class WechatPayConfig {
@Value("${wechat.pay.appid}")
private String appid;
@Value("${wechat.pay.mchid}")
private String mchid;
@Value("${wechat.pay.api-v3-key}")
private String apiV3Key;
@Bean
public WechatPayService wechatPayService() throws IOException {
// 加载商户私钥
PrivateKey privateKey = loadPrivateKey(privateKeyPath);
// 构建配置
Config config = new RSAAutoCertificateConfig.Builder()
.merchantId(mchid)
.privateKeyFromPath(privateKeyPath)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3Key)
.build();
return new WechatPayService.Builder().config(config).build();
}
private PrivateKey loadPrivateKey(String path) throws IOException {
// 实现私钥加载逻辑
String privateKeyContent = new String(Files.readAllBytes(Paths.get(path)));
return PemUtil.loadPrivateKey(privateKeyContent);
}
}
3. 支付功能实现
3.1 统一下单接口实现
创建支付服务类处理统一下单逻辑:
@Service
public class WechatPayService {
@Autowired
private WechatPayService wechatPayService;
@Value("${wechat.pay.appid}")
private String appid;
@Value("${wechat.pay.notify-url}")
private String notifyUrl;
public Map<String, String> jsapiPay(String outTradeNo, Integer totalAmount,
String description, String openid) throws IOException {
// 构建支付请求
PrepayRequest request = new PrepayRequest();
request.setAppid(appid);
request.setMchid(mchid);
request.setDescription(description);
request.setOutTradeNo(outTradeNo);
request.setNotifyUrl(notifyUrl);
// 设置金额
Amount amount = new Amount();
amount.setTotal(totalAmount); // 单位:分
amount.setCurrency("CNY");
request.setAmount(amount);
// 设置支付者
Payer payer = new Payer();
payer.setOpenid(openid);
request.setPayer(payer);
// 调用下单接口
PrepayResponse response = wechatPayService.prepay(request);
// 生成前端支付参数
return generatePaySignature(response.getPrepayId());
}
private Map<String, String> generatePaySignature(String prepayId) {
String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
String nonceStr = UUID.randomUUID().toString().replace("-", "");
String packageStr = "prepay_id=" + prepayId;
// 生成签名
String sign = generateSign(appid, timeStamp, nonceStr, packageStr);
Map<String, String> result = new HashMap<>();
result.put("appId", appid);
result.put("timeStamp", timeStamp);
result.put("nonceStr", nonceStr);
result.put("package", packageStr);
result.put("signType", "RSA");
result.put("paySign", sign);
return result;
}
}
3.2 支付回调处理
支付回调接口用于接收微信支付的异步通知:
@RestController
@RequestMapping("/wechat/pay")
public class WechatPayController {
@Autowired
private WechatPayService wechatPayService;
@PostMapping("/callback")
public String payCallback(HttpServletRequest request) {
try {
// 读取回调数据
String body = readRequestBody(request);
// 获取微信回调头信息
String signature = request.getHeader("Wechatpay-Signature");
String nonce = request.getHeader("Wechatpay-Nonce");
String timestamp = request.getHeader("Wechatpay-Timestamp");
String serial = request.getHeader("Wechatpay-Serial");
// 验证签名
if (!verifySignature(signature, nonce, timestamp, body, serial)) {
return buildErrorResponse("签名验证失败");
}
// 解密回调数据
String plainText = decryptBody(body);
// 处理业务逻辑(更新订单状态等)
wechatPayService.processPaymentResult(plainText);
return buildSuccessResponse();
} catch (Exception e) {
return buildErrorResponse("处理失败: " + e.getMessage());
}
}
private String decryptBody(String encryptedBody) throws GeneralSecurityException {
JSONObject jsonObject = JSON.parseObject(encryptedBody);
JSONObject resource = jsonObject.getJSONObject("resource");
String ciphertext = resource.getString("ciphertext");
String associatedData = resource.getString("associated_data");
String nonce = resource.getString("nonce");
// 使用AES-GCM解密
AesUtil aesUtil = new AesUtil(apiV3Key.getBytes(StandardCharsets.UTF_8));
return aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),
nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
}
}
4. 退款功能实现
4.1 退款接口实现
在支付服务类中添加退款方法:
@Service
public class WechatPayService {
public RefundResponse refund(String outTradeNo, String outRefundNo,
Integer refundFee, Integer totalFee) throws IOException {
RefundRequest request = new RefundRequest();
request.setOutTradeNo(outTradeNo);
request.setOutRefundNo(outRefundNo);
// 设置退款金额
AmountRefund amount = new AmountRefund();
amount.setRefund(refundFee);
amount.setTotal(totalFee);
amount.setCurrency("CNY");
request.setAmount(amount);
// 调用退款接口
return wechatPayService.refund(request);
}
}
4.2 退款回调处理
退款结果也需要异步回调通知:
@PostMapping("/refund/callback")
public String refundCallback(HttpServletRequest request) {
try {
// 处理逻辑与支付回调类似
String body = readRequestBody(request);
// 验证签名
if (!verifyRefundSignature(request, body)) {
return buildErrorResponse("退款回调签名验证失败");
}
// 解密退款结果
String plainText = decryptBody(body);
// 处理退款业务逻辑
wechatPayService.processRefundResult(plainText);
return buildSuccessResponse();
} catch (Exception e) {
return buildErrorResponse("退款处理失败: " + e.getMessage());
}
}
5. 关键注意事项
5.1 安全性处理
- 签名验证:所有回调必须验证微信签名,防止伪造请求
- 数据解密:回调中的敏感信息使用AEAD_AES_256_GCM算法加密,需要解密处理
- 幂等性处理:支付和退款回调需要处理重复通知,确保业务幂等性
5.2 异常处理
- 网络超时:设置合理的超时时间,实现重试机制
- 证书管理:定期更新平台证书,处理证书过期异常
- 金额一致性:确保支付金额、退款金额与订单一致,避免金额不一致错误
5.3 回调接口要求
- 公网可访问:回调地址必须是HTTPS且公网可访问
- 快速响应:处理完成后需要立即返回success,否则微信会重试通知
- 跳过拦截器:确保回调接口不被权限拦截器拦截
以上步骤涵盖了Spring Boot对接微信支付V3的核心流程。实际开发中,请结合微信支付官方文档和业务需求进行适当调整。如果您在具体实现过程中遇到问题,可以参考微信支付官方文档或社区资源获取更多帮助。