9.0 KiB
9.0 KiB
微信支付集成指南
概述
本项目集成了微信支付功能,支持JSAPI支付、支付回调处理、退款等功能。支付网关采用第三方服务,简化了支付对接流程。
功能特性
- ✅ JSAPI支付(微信公众号支付)
- ✅ 支付回调处理
- ✅ 订单状态更新
- ✅ 退款功能
- ✅ 支付日志记录
- ✅ 支付状态查询
配置步骤
1. 微信支付配置
1.1 获取支付配置
联系支付网关服务商获取以下配置:
- AppId: 微信公众号AppId
- Secret: 微信公众号Secret
- BizId: 支付业务ID
- AppKey: 支付密钥
- PayUrl: 支付接口地址
- RefundUrl: 退款接口地址
1.2 系统配置
修改 application-dev.yml 配置文件:
wxshop:
appid: wx9922dfbb0d4cd7bb
secret: 7c7ef0dbb90b6be2abc8c269357f980a
pay:
biz_id: wxshop
old_biz_id: wxshop_old
appkey: wxshop202503081132
pay_url: http://222.218.10.217:7890/open/trade/wx/jsapi/precreate
refund_url: http://222.218.10.217:7890/open/trade/refund
2. 数据库准备
2.1 支付日志表
CREATE TABLE `payment_operation_log` (
`id` bigint NOT NULL AUTO_INCREMENT,
`order_no` varchar(64) NOT NULL COMMENT '订单号',
`operation_type` varchar(50) NOT NULL COMMENT '操作类型',
`request_data` text COMMENT '请求数据',
`response_data` text COMMENT '响应数据',
`status` tinyint DEFAULT '1' COMMENT '状态',
`error_msg` varchar(500) DEFAULT NULL COMMENT '错误信息',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_order_no` (`order_no`)
);
核心功能
1. 创建支付订单
1.1 支付请求
POST /payment/create
Content-Type: application/json
{
"orderId": "2025030811320001",
"amount": 99.99,
"openid": "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o",
"payType": "JSAPI",
"subject": "商品订单",
"body": "商品描述"
}
1.2 支付响应
{
"code": 200,
"msg": "success",
"data": {
"prepayId": "wx20250308113200abc123",
"paySign": "BDF0099C9FF443C4DC5C5D68C4B97C3F",
"timestamp": "1657794651",
"nonceStr": "1657794651",
"package": "prepay_id=wx20250308113200abc123"
}
}
2. 支付回调
2.1 回调接口
POST /payment/callback
Content-Type: application/xml
2.2 回调数据示例
<xml>
<appid><![CDATA[wx9922dfbb0d4cd7bb]]></appid>
<bank_type><![CDATA[CFT]]></bank_type>
<cash_fee><![CDATA[1]]></cash_fee>
<fee_type><![CDATA[CNY]]></fee_type>
<is_subscribe><![CDATA[N]]></is_subscribe>
<mch_id><![CDATA[1600000000]]></mch_id>
<nonce_str><![CDATA[1657794651]]></nonce_str>
<openid><![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]></openid>
<out_trade_no><![CDATA[2025030811320001]]></out_trade_no>
<result_code><![CDATA[SUCCESS]]></result_code>
<return_code><![CDATA[SUCCESS]]></return_code>
<sign><![CDATA[BDF0099C9FF443C4DC5C5D68C4B97C3F]]></sign>
<time_end><![CDATA[20140903131540]]></time_end>
<total_fee>1</total_fee>
<trade_type><![CDATA[JSAPI]]></trade_type>
<transaction_id><![CDATA[1004400740201409030005092168]]></transaction_id>
</xml>
2.3 回调响应
<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
</xml>
3. 退款功能
3.1 退款请求
POST /payment/refund
Content-Type: application/json
{
"orderNo": "2025030811320001",
"refundAmount": 99.99,
"refundReason": "用户申请退款",
"refundNo": "REF2025030811320001"
}
3.2 退款响应
{
"code": 200,
"msg": "success",
"data": {
"refundId": "REF2025030811320001",
"status": "PROCESSING",
"refundTime": "2025-03-08 11:32:00"
}
}
代码实现
1. 支付服务
@Service
@RequiredArgsConstructor
public class PaymentService {
private final PaymentGateway paymentGateway;
private final PaymentOperationLogService logService;
public WxJsApiPreCreateResponse createPayment(WxJsApiPreCreateRequest request) {
// 记录请求日志
PaymentOperationLog log = createRequestLog(request);
try {
// 调用支付网关
WxJsApiPreCreateResponse response = paymentGateway.preCreate(request);
// 记录响应日志
updateResponseLog(log, response, true);
return response;
} catch (Exception e) {
// 记录错误日志
updateErrorLog(log, e.getMessage());
throw new ApiException("支付创建失败: " + e.getMessage());
}
}
}
2. 支付网关
@Component
public class PaymentGateway {
@Value("${wxshop.pay.pay-url}")
private String payUrl;
@Value("${wxshop.pay.appkey}")
private String appKey;
public WxJsApiPreCreateResponse preCreate(WxJsApiPreCreateRequest request) {
// 构建请求参数
Map<String, String> params = buildParams(request);
// 生成签名
String sign = SignUtils.generateSign(params, appKey);
params.put("sign", sign);
// 发送请求
String response = HttpUtil.post(payUrl, params);
// 解析响应
return parseResponse(response);
}
}
3. 签名工具
public class SignUtils {
public static String generateSign(Map<String, String> params, String appKey) {
// 参数排序
List<String> keys = new ArrayList<>(params.keySet());
Collections.sort(keys);
// 拼接参数
StringBuilder sb = new StringBuilder();
for (String key : keys) {
String value = params.get(key);
if (value != null && !value.isEmpty()) {
sb.append(key).append("=").append(value).append("&");
}
}
sb.append("key=").append(appKey);
// MD5加密
return DigestUtils.md5Hex(sb.toString()).toUpperCase();
}
}
支付流程
1. 支付创建流程
sequenceDiagram
participant Client
participant Backend
participant PaymentGateway
participant WeChat
Client->>Backend: 创建支付订单
Backend->>PaymentGateway: 预支付请求
PaymentGateway->>WeChat: 统一下单
WeChat-->>PaymentGateway: 返回预支付ID
PaymentGateway-->>Backend: 返回支付参数
Backend-->>Client: 返回前端支付参数
2. 支付回调流程
sequenceDiagram
participant WeChat
participant Backend
participant Database
WeChat->>Backend: 支付结果通知
Backend->>Backend: 验证签名
Backend->>Database: 更新订单状态
Backend-->>WeChat: 返回成功响应
错误处理
1. 支付错误码
| 错误码 | 说明 | 处理建议 |
|---|---|---|
SYSTEMERROR |
系统错误 | 重试操作 |
ORDERPAID |
订单已支付 | 检查订单状态 |
OUT_TRADE_NO_USED |
商户订单号重复 | 使用新订单号 |
NOTENOUGH |
余额不足 | 提示用户 |
APPID_NOT_EXIST |
AppID不存在 | 检查配置 |
2. 异常处理
@RestControllerAdvice
public class PaymentExceptionHandler {
@ExceptionHandler(PaymentException.class)
public ResponseDTO<Void> handlePaymentException(PaymentException e) {
log.error("支付异常: {}", e.getMessage(), e);
return ResponseDTO.fail(e.getCode(), e.getMessage());
}
@ExceptionHandler(Exception.class)
public ResponseDTO<Void> handleException(Exception e) {
log.error("系统异常: {}", e.getMessage(), e);
return ResponseDTO.fail(500, "系统繁忙,请稍后重试");
}
}
安全注意事项
1. 数据安全
- 支付密钥妥善保管
- 敏感数据传输使用HTTPS
- 支付回调验证签名
- 防止重复支付
2. 业务安全
- 订单金额校验
- 用户身份验证
- 防止SQL注入
- 日志记录完整
监控和日志
1. 监控指标
- 支付成功率
- 支付平均耗时
- 退款成功率
- 回调处理成功率
2. 日志记录
- 支付请求/响应日志
- 回调处理日志
- 错误日志
- 性能日志
测试建议
1. 单元测试
@SpringBootTest
class PaymentServiceTest {
@Autowired
private PaymentService paymentService;
@Test
void testCreatePayment() {
WxJsApiPreCreateRequest request = new WxJsApiPreCreateRequest();
request.setOrderNo("TEST001");
request.setAmount(new BigDecimal("0.01"));
request.setOpenid("test_openid");
WxJsApiPreCreateResponse response = paymentService.createPayment(request);
assertNotNull(response);
assertNotNull(response.getPrepayId());
}
}
2. 集成测试
- 支付流程完整测试
- 回调处理测试
- 退款流程测试
- 异常场景测试
性能优化
1. 缓存优化
- 支付配置缓存
- 订单状态缓存
- 用户信息缓存
2. 异步处理
- 支付日志异步记录
- 通知消息异步发送
- 统计报表异步生成
3. 数据库优化
- 支付日志表分表
- 订单表索引优化
- 定期清理历史数据