Browse Source

大改:重构项目

main
科技小王子 4 weeks ago
parent
commit
c2d211724a
  1. 222
      src/main/java/com/gxwebsoft/common/core/utils/WechatPayDiagnostic.java
  2. 93
      src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java

222
src/main/java/com/gxwebsoft/common/core/utils/WechatPayDiagnostic.java

@ -0,0 +1,222 @@
package com.gxwebsoft.common.core.utils;
import com.gxwebsoft.common.system.entity.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
/**
* 微信支付配置诊断工具
* 用于排查微信支付签名验证失败等问题
*
* @author 科技小王子
* @since 2025-07-27
*/
@Slf4j
@Component
public class WechatPayDiagnostic {
/**
* 诊断微信支付配置
*
* @param payment 支付配置
* @param privateKeyPath 私钥路径
* @param environment 环境标识
*/
public void diagnosePaymentConfig(Payment payment, String privateKeyPath, String environment) {
log.info("=== 微信支付配置诊断开始 ===");
log.info("环境: {}", environment);
// 1. 检查支付配置基本信息
checkBasicConfig(payment);
// 2. 检查证书文件
checkCertificateFiles(payment, privateKeyPath, environment);
// 3. 检查配置完整性
checkConfigCompleteness(payment);
log.info("=== 微信支付配置诊断结束 ===");
}
/**
* 检查基本配置信息
*/
private void checkBasicConfig(Payment payment) {
log.info("--- 基本配置检查 ---");
if (payment == null) {
log.error("❌ 支付配置为空");
return;
}
log.info("支付配置ID: {}", payment.getId());
log.info("支付方式名称: {}", payment.getName());
log.info("支付类型: {}", payment.getType());
log.info("支付代码: {}", payment.getCode());
log.info("状态: {}", payment.getStatus());
// 检查关键字段
checkField("应用ID", payment.getAppId());
checkField("商户号", payment.getMchId());
checkField("商户证书序列号", payment.getMerchantSerialNumber());
checkField("API密钥", payment.getApiKey(), true);
}
/**
* 检查证书文件
*/
private void checkCertificateFiles(Payment payment, String privateKeyPath, String environment) {
log.info("--- 证书文件检查 ---");
// 检查私钥文件
if (privateKeyPath != null) {
checkFileExists("私钥文件", privateKeyPath);
}
// 生产环境检查证书文件
if (!"dev".equals(environment)) {
if (payment.getApiclientCert() != null) {
log.info("商户证书文件配置: {}", payment.getApiclientCert());
}
if (payment.getPubKey() != null) {
log.info("公钥文件配置: {}", payment.getPubKey());
log.info("公钥ID: {}", payment.getPubKeyId());
}
}
}
/**
* 检查配置完整性
*/
private void checkConfigCompleteness(Payment payment) {
log.info("--- 配置完整性检查 ---");
boolean isComplete = true;
if (isEmpty(payment.getMchId())) {
log.error("❌ 商户号未配置");
isComplete = false;
}
if (isEmpty(payment.getMerchantSerialNumber())) {
log.error("❌ 商户证书序列号未配置");
isComplete = false;
}
if (isEmpty(payment.getApiKey())) {
log.error("❌ API密钥未配置");
isComplete = false;
}
if (isEmpty(payment.getAppId())) {
log.error("❌ 应用ID未配置");
isComplete = false;
}
if (isComplete) {
log.info("✅ 配置完整性检查通过");
} else {
log.error("❌ 配置不完整,请补充缺失的配置项");
}
}
/**
* 检查字段是否为空
*/
private void checkField(String fieldName, String value) {
checkField(fieldName, value, false);
}
/**
* 检查字段是否为空
*/
private void checkField(String fieldName, String value, boolean isSensitive) {
if (isEmpty(value)) {
log.warn("⚠️ {}: 未配置", fieldName);
} else {
if (isSensitive) {
log.info("✅ {}: 已配置(长度:{})", fieldName, value.length());
} else {
log.info("✅ {}: {}", fieldName, value);
}
}
}
/**
* 检查文件是否存在
*/
private void checkFileExists(String fileName, String filePath) {
try {
File file = new File(filePath);
if (file.exists() && file.isFile()) {
log.info("✅ {}: 文件存在 - {}", fileName, filePath);
log.info(" 文件大小: {} bytes", file.length());
// 检查文件内容格式
if (filePath.endsWith(".pem")) {
checkPemFileFormat(fileName, filePath);
}
} else {
log.error("❌ {}: 文件不存在 - {}", fileName, filePath);
}
} catch (Exception e) {
log.error("❌ {}: 检查文件时出错 - {} ({})", fileName, filePath, e.getMessage());
}
}
/**
* 检查PEM文件格式
*/
private void checkPemFileFormat(String fileName, String filePath) {
try {
String content = Files.readString(Paths.get(filePath));
if (content.contains("-----BEGIN") && content.contains("-----END")) {
log.info("✅ {}: PEM格式正确", fileName);
} else {
log.warn("⚠️ {}: PEM格式可能有问题", fileName);
}
} catch (Exception e) {
log.warn("⚠️ {}: 无法读取文件内容进行格式检查 ({})", fileName, e.getMessage());
}
}
/**
* 检查字符串是否为空
*/
private boolean isEmpty(String str) {
return str == null || str.trim().isEmpty();
}
/**
* 生成诊断报告
*/
public String generateDiagnosticReport(Payment payment, String environment) {
StringBuilder report = new StringBuilder();
report.append("🔍 微信支付配置诊断报告\n");
report.append("========================\n\n");
report.append("环境: ").append(environment).append("\n");
report.append("租户ID: ").append(payment != null ? payment.getTenantId() : "未知").append("\n");
report.append("商户号: ").append(payment != null ? payment.getMchId() : "未配置").append("\n");
report.append("应用ID: ").append(payment != null ? payment.getAppId() : "未配置").append("\n\n");
report.append("🚨 常见问题排查:\n");
report.append("1. 商户证书序列号是否正确\n");
report.append("2. APIv3密钥是否正确\n");
report.append("3. 私钥文件是否正确\n");
report.append("4. 微信支付平台证书是否过期\n");
report.append("5. 网络连接是否正常\n\n");
report.append("💡 建议解决方案:\n");
report.append("1. 使用自动证书配置(RSAAutoCertificateConfig)\n");
report.append("2. 在微信商户平台重新下载证书\n");
report.append("3. 检查商户平台API安全设置\n");
return report.toString();
}
}

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

@ -11,6 +11,7 @@
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.common.core.utils.CertificateLoader;
import com.gxwebsoft.common.core.service.PaymentCacheService;
import com.gxwebsoft.common.core.utils.WechatPayDiagnostic;
import com.gxwebsoft.common.system.entity.Payment;
import lombok.extern.slf4j.Slf4j;
import com.gxwebsoft.common.system.param.PaymentParam;
@ -73,6 +74,8 @@ import com.gxwebsoft.common.core.service.PaymentCacheService;
private PaymentCacheService paymentCacheService;
@Resource
private WechatCertAutoConfig wechatCertAutoConfig;
@Resource
private WechatPayDiagnostic wechatPayDiagnostic;
@Override
public PageResult<ShopOrder> pageRel(ShopOrderParam param) {
@ -154,7 +157,14 @@ import com.gxwebsoft.common.core.service.PaymentCacheService;
if (StrUtil.isNotBlank(payment.getNotifyUrl())) {
request.setNotifyUrl(payment.getNotifyUrl().concat("/").concat(order.getTenantId().toString()));
}
System.out.println("=== 发起微信支付请求 ===");
System.out.println("请求参数: " + request);
PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
System.out.println("=== 微信支付响应成功 ===");
System.out.println("预支付ID: " + response.getPackageVal());
orderInfo.put("provider", "wxpay");
orderInfo.put("timeStamp", response.getTimeStamp());
orderInfo.put("nonceStr", response.getNonceStr());
@ -167,6 +177,26 @@ import com.gxwebsoft.common.core.service.PaymentCacheService;
System.err.println("=== 创建微信支付订单失败 ===");
System.err.println("错误信息: " + e.getMessage());
System.err.println("错误类型: " + e.getClass().getName());
// 特殊处理签名验证失败的情况
if (e.getMessage() != null && e.getMessage().contains("signature is incorrect")) {
System.err.println("🔍 签名验证失败诊断:");
System.err.println("1. 检查商户证书序列号是否正确");
System.err.println("2. 检查APIv3密钥是否正确");
System.err.println("3. 检查私钥文件是否正确");
System.err.println("4. 检查微信支付平台证书是否过期");
System.err.println("5. 建议使用自动证书配置避免证书管理问题");
System.err.println("当前支付配置:");
try {
final Payment paymentInfo = getPayment(order);
System.err.println(" - 商户号: " + paymentInfo.getMchId());
System.err.println(" - 序列号: " + paymentInfo.getMerchantSerialNumber());
System.err.println(" - 环境: " + active);
} catch (Exception ex) {
System.err.println(" - 无法获取支付配置信息: " + ex.getMessage());
}
}
e.printStackTrace();
throw new RuntimeException("创建支付订单失败:" + e.getMessage(), e);
}
@ -257,6 +287,10 @@ import com.gxwebsoft.common.core.service.PaymentCacheService;
String apiclientCert = null;
String pubKey = null;
// 运行配置诊断
System.out.println("=== 运行微信支付配置诊断 ===");
wechatPayDiagnostic.diagnosePaymentConfig(payment, null, active);
// 开发环境配置 - 使用自动证书配置
if (active.equals("dev")) {
// 构建包含租户号的证书路径: dev/wechat/{tenantId}/
@ -278,6 +312,9 @@ import com.gxwebsoft.common.core.service.PaymentCacheService;
System.out.println("私钥完整路径: " + privateKey);
System.out.println("证书加载完成 - 私钥文件: " + privateKey);
System.out.println("使用自动证书配置,无需手动加载微信支付平台证书");
// 更新诊断信息,包含私钥路径
wechatPayDiagnostic.diagnosePaymentConfig(payment, privateKey, active);
} else {
// 生产环境配置 - 从容器证书目录加载
final String certRootPath = certConfig.getCertRootPath(); // /www/wwwroot/file.ws
@ -358,23 +395,45 @@ import com.gxwebsoft.common.core.service.PaymentCacheService;
throw new RuntimeException("微信支付配置失败,请先在商户平台开启API安全功能", e);
}
} else {
// 生产环境兼容公钥配置
if (payment.getPubKey() != null && !payment.getPubKey().isEmpty()) {
config = new RSAPublicKeyConfig.Builder()
.merchantId(payment.getMchId())
.privateKeyFromPath(privateKey)
.publicKeyFromPath(pubKey)
.publicKeyId(payment.getPubKeyId())
.merchantSerialNumber(payment.getMerchantSerialNumber())
.apiV3Key(payment.getApiKey())
.build();
} else {
config = new RSAConfig.Builder()
.merchantId(payment.getMchId())
.privateKeyFromPath(privateKey)
.merchantSerialNumber(payment.getMerchantSerialNumber())
.wechatPayCertificatesFromPath(apiclientCert)
.build();
// 生产环境优先使用自动证书配置
System.out.println("=== 生产环境使用自动证书配置 ===");
System.out.println("商户号: " + payment.getMchId());
System.out.println("序列号: " + payment.getMerchantSerialNumber());
System.out.println("API密钥: 已配置(长度:" + payment.getApiKey().length() + ")");
try {
// 优先使用自动证书配置,避免证书过期和序列号不匹配问题
config = wechatCertAutoConfig.createAutoConfig(
payment.getMchId(),
privateKey,
payment.getMerchantSerialNumber(),
payment.getApiKey()
);
System.out.println("✅ 生产环境自动证书配置成功");
} catch (Exception autoConfigException) {
System.err.println("⚠️ 自动证书配置失败,回退到手动证书配置");
System.err.println("自动配置错误: " + autoConfigException.getMessage());
// 回退到手动证书配置
if (payment.getPubKey() != null && !payment.getPubKey().isEmpty()) {
System.out.println("使用RSA公钥配置");
config = new RSAPublicKeyConfig.Builder()
.merchantId(payment.getMchId())
.privateKeyFromPath(privateKey)
.publicKeyFromPath(pubKey)
.publicKeyId(payment.getPubKeyId())
.merchantSerialNumber(payment.getMerchantSerialNumber())
.apiV3Key(payment.getApiKey())
.build();
} else {
System.out.println("使用RSA证书配置");
config = new RSAConfig.Builder()
.merchantId(payment.getMchId())
.privateKeyFromPath(privateKey)
.merchantSerialNumber(payment.getMerchantSerialNumber())
.wechatPayCertificatesFromPath(apiclientCert)
.build();
}
}
}

Loading…
Cancel
Save