Browse Source

修复微信支付,兼容公钥模块

main
科技小王子 4 weeks ago
parent
commit
c1a3d674ec
  1. 136
      docs/PRODUCTION_PATH_FIX.md
  2. 5
      src/main/java/com/gxwebsoft/common/core/service/PaymentCacheService.java
  3. 3
      src/main/java/com/gxwebsoft/common/system/mapper/xml/PaymentMapper.xml
  4. 4
      src/main/java/com/gxwebsoft/common/system/param/PaymentParam.java
  5. 17
      src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java

136
docs/PRODUCTION_PATH_FIX.md

@ -0,0 +1,136 @@
# 生产环境公钥路径修复
## 问题描述
**错误信息**:`Docker挂载卷中找不到证书文件:/www/wwwroot/file.ws/20250114/0f65a8517c284acb90aa83dd0c23e8f6.pem`
**正确路径**:`/www/wwwroot/file.ws/file/20250114/0f65a8517c284acb90aa83dd0c23e8f6.pem`
**问题原因**:生产环境的公钥路径缺少 `/file` 目录前缀
## 修复方案
### 🔧 方案B:代码逻辑修正(已实施)
在生产环境的公钥处理代码中添加路径修正逻辑:
```java
// 生产环境处理公钥路径 - 添加 /file 前缀
String pubKeyPath = payment.getPubKey();
// 如果路径不是以 /file 开头,需要添加 /file 前缀
if (!pubKeyPath.startsWith("/file/") && !pubKeyPath.startsWith("file/")) {
pubKeyPath = "file/" + pubKeyPath;
System.out.println("生产环境公钥路径修正: " + payment.getPubKey() + " -> " + pubKeyPath);
} else {
System.out.println("生产环境公钥路径: " + pubKeyPath);
}
String pubKeyFile = certificateLoader.loadCertificatePath(pubKeyPath);
```
### 📋 修复逻辑
1. **开发环境**
- 固定使用 `wechatpay_public_key.pem`
- 路径:`dev/wechat/{tenantId}/wechatpay_public_key.pem`
2. **生产环境**
- 检查数据库中的 `pubKey` 路径
- 如果不以 `file/` 开头,自动添加 `file/` 前缀
- 最终路径:`file/{原始路径}`
### 🎯 预期效果
**修正前的路径**:
```
数据库配置: 20250114/0f65a8517c284acb90aa83dd0c23e8f6.pem
实际查找: /www/wwwroot/file.ws/20250114/0f65a8517c284acb90aa83dd0c23e8f6.pem
结果: ❌ 文件不存在
```
**修正后的路径**:
```
数据库配置: 20250114/0f65a8517c284acb90aa83dd0c23e8f6.pem
路径修正: file/20250114/0f65a8517c284acb90aa83dd0c23e8f6.pem
实际查找: /www/wwwroot/file.ws/file/20250114/0f65a8517c284acb90aa83dd0c23e8f6.pem
结果: ✅ 文件找到
```
### 📊 日志输出
**成功的日志**:
```
=== 生产环境检测到公钥配置,使用RSA公钥模式 ===
公钥文件路径: 20250114/0f65a8517c284acb90aa83dd0c23e8f6.pem
公钥ID: YOUR_PUBLIC_KEY_ID
生产环境公钥路径修正: 20250114/0f65a8517c284acb90aa83dd0c23e8f6.pem -> file/20250114/0f65a8517c284acb90aa83dd0c23e8f6.pem
✅ 生产环境公钥文件加载成功: /www/wwwroot/file.ws/file/20250114/0f65a8517c284acb90aa83dd0c23e8f6.pem
✅ 生产环境RSA公钥配置成功
```
**如果路径已经正确**:
```
=== 生产环境检测到公钥配置,使用RSA公钥模式 ===
公钥文件路径: file/20250114/0f65a8517c284acb90aa83dd0c23e8f6.pem
公钥ID: YOUR_PUBLIC_KEY_ID
生产环境公钥路径: file/20250114/0f65a8517c284acb90aa83dd0c23e8f6.pem
✅ 生产环境公钥文件加载成功: /www/wwwroot/file.ws/file/20250114/0f65a8517c284acb90aa83dd0c23e8f6.pem
✅ 生产环境RSA公钥配置成功
```
### 🔍 兼容性
这个修复方案具有很好的兼容性:
1. **向后兼容**
- 如果数据库中已经配置了正确的路径(以 `file/` 开头),不会进行修正
- 如果数据库中是旧的路径格式,会自动添加 `file/` 前缀
2. **多种路径格式支持**
- `20250114/xxx.pem``file/20250114/xxx.pem`
- `file/20250114/xxx.pem``file/20250114/xxx.pem`(不变)
- `/file/20250114/xxx.pem``/file/20250114/xxx.pem`(不变)
### 🚀 测试验证
现在可以重新测试支付订单创建:
1. **确认数据库配置**
```sql
SELECT tenant_id, pub_key, pub_key_id
FROM sys_payment
WHERE tenant_id = 10547 AND type = 0;
```
2. **重新创建支付订单**
3. **查看日志输出**
- 关注 "生产环境公钥路径修正" 的输出
- 确认最终路径是否正确
### 📁 文件结构
**生产环境文件结构**:
```
/www/wwwroot/file.ws/file/
├── 20250114/
│ └── 0f65a8517c284acb90aa83dd0c23e8f6.pem
├── wechat/
│ └── 10547/
│ ├── apiclient_key.pem
│ ├── apiclient_cert.pem
│ └── public_key.pem
└── ...
```
### 🎉 修复完成
通过这个修复:
1. ✅ 解决了生产环境公钥路径缺少 `/file` 前缀的问题
2. ✅ 保持了向后兼容性
3. ✅ 支持多种路径格式
4. ✅ 提供了详细的日志输出用于调试
现在生产环境应该能够正确找到公钥文件,成功使用RSA公钥配置,避免证书相关错误。

5
src/main/java/com/gxwebsoft/common/core/service/PaymentCacheService.java

@ -44,7 +44,7 @@ public class PaymentCacheService {
if (ObjectUtil.isNotEmpty(payment)) {
log.debug("从缓存获取支付配置成功: {}", primaryKey);
// return payment;
return payment;
}
// 2. 如果 Payment:1* 格式不存在,尝试原有格式
@ -55,13 +55,14 @@ public class PaymentCacheService {
log.debug("从兜底缓存获取支付配置成功: {}", fallbackKey);
// 将查询结果缓存到 Payment:1* 格式
redisUtil.set(primaryKey, payment);
// return payment;
return payment;
}
// 3. 最后从数据库查询
log.debug("从数据库查询支付配置, payType: {}, tenantId: {}", payType, tenantId);
PaymentParam paymentParam = new PaymentParam();
paymentParam.setType(payType);
paymentParam.setTenantId(tenantId); // 设置租户ID进行过滤
List<Payment> payments = paymentService.listRel(paymentParam);
if (payments.isEmpty()) {

3
src/main/java/com/gxwebsoft/common/system/mapper/xml/PaymentMapper.xml

@ -55,6 +55,9 @@
<if test="param.deleted == null">
AND a.deleted = 0
</if>
<if test="param.tenantId != null">
AND a.tenant_id = #{param.tenantId}
</if>
<if test="param.createTimeStart != null">
AND a.create_time &gt;= #{param.createTimeStart}
</if>

4
src/main/java/com/gxwebsoft/common/system/param/PaymentParam.java

@ -74,4 +74,8 @@ public class PaymentParam extends BaseParam {
@QueryField(type = QueryType.EQ)
private Integer deleted;
@Schema(description = "租户ID")
@QueryField(type = QueryType.EQ)
private Integer tenantId;
}

17
src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java

@ -252,6 +252,9 @@ import com.gxwebsoft.common.core.service.PaymentCacheService;
* @return
*/
public Payment getPayment(ShopOrder order) {
// 先清除可能的错误缓存
paymentCacheService.removePaymentConfig(order.getPayType().toString(), order.getTenantId());
Payment payment = paymentCacheService.getPaymentConfig(order.getPayType(), order.getTenantId());
// 添加详细的支付配置检查
@ -532,8 +535,18 @@ import com.gxwebsoft.common.core.service.PaymentCacheService;
System.out.println("公钥ID: " + payment.getPubKeyId());
try {
// 生产环境直接使用数据库中存储的完整路径
String pubKeyFile = certificateLoader.loadCertificatePath(payment.getPubKey());
// 生产环境处理公钥路径
String pubKeyPath = payment.getPubKey();
// 如果路径不是以 /file 开头,需要添加 /file 前缀
if (!pubKeyPath.startsWith("/file/") && !pubKeyPath.startsWith("file/")) {
pubKeyPath = "file/" + pubKeyPath;
System.out.println("生产环境公钥路径修正: " + payment.getPubKey() + " -> " + pubKeyPath);
} else {
System.out.println("生产环境公钥路径: " + pubKeyPath);
}
String pubKeyFile = certificateLoader.loadCertificatePath(pubKeyPath);
System.out.println("✅ 生产环境公钥文件加载成功: " + pubKeyFile);
config = new RSAPublicKeyConfig.Builder()

Loading…
Cancel
Save