Browse Source
- 新增支付配置诊断SQL脚本 - 添加测试控制器和微信支付诊断控制器 - 实现支付配置检查、快速测试和缓存清理等功能 -优化支付服务和订单创建流程- 更新相关实体和DTO以支持新功能main
10 changed files with 821 additions and 8 deletions
@ -0,0 +1,140 @@ |
|||
-- 支付配置诊断SQL脚本 |
|||
-- 用于诊断"Value must not be null!"错误 |
|||
|
|||
-- 1. 检查所有租户的支付配置完整性 |
|||
SELECT |
|||
tenant_id, |
|||
name, |
|||
type, |
|||
mch_id, |
|||
app_id, |
|||
merchant_serial_number, |
|||
api_key, |
|||
apiclient_key, |
|||
apiclient_cert, |
|||
pub_key, |
|||
pub_key_id, |
|||
status, |
|||
-- 配置完整性检查 |
|||
CASE |
|||
WHEN mch_id IS NULL OR mch_id = '' THEN '❌ 商户号缺失' |
|||
WHEN app_id IS NULL OR app_id = '' THEN '❌ 应用ID缺失' |
|||
WHEN merchant_serial_number IS NULL OR merchant_serial_number = '' THEN '❌ 证书序列号缺失' |
|||
WHEN api_key IS NULL OR api_key = '' THEN '❌ API密钥缺失' |
|||
WHEN LENGTH(api_key) != 32 THEN '❌ API密钥长度错误' |
|||
ELSE '✅ 基础配置完整' |
|||
END AS basic_config_status, |
|||
-- 证书配置模式检查 |
|||
CASE |
|||
WHEN pub_key IS NOT NULL AND pub_key != '' AND pub_key_id IS NOT NULL AND pub_key_id != '' |
|||
THEN '🔑 公钥模式' |
|||
WHEN apiclient_key IS NOT NULL AND apiclient_key != '' AND apiclient_cert IS NOT NULL AND apiclient_cert != '' |
|||
THEN '📜 证书模式' |
|||
ELSE '⚠️ 自动证书模式' |
|||
END AS cert_mode, |
|||
-- 状态检查 |
|||
CASE |
|||
WHEN status = 1 THEN '✅ 已启用' |
|||
ELSE '❌ 未启用' |
|||
END AS status_check |
|||
FROM sys_payment |
|||
WHERE type = 0 -- 微信支付 |
|||
ORDER BY tenant_id; |
|||
|
|||
-- 2. 检查特定租户的详细配置(请替换为实际的租户ID) |
|||
-- 如果您知道具体的租户ID,请取消注释并修改下面的查询 |
|||
/* |
|||
SELECT |
|||
'=== 租户配置详情 ===' as section, |
|||
tenant_id, |
|||
name, |
|||
mch_id as '商户号', |
|||
app_id as '应用ID', |
|||
merchant_serial_number as '证书序列号', |
|||
CASE |
|||
WHEN api_key IS NOT NULL AND api_key != '' |
|||
THEN CONCAT('已配置(长度:', LENGTH(api_key), ')') |
|||
ELSE '未配置' |
|||
END as 'API密钥状态', |
|||
apiclient_key as '私钥文件', |
|||
apiclient_cert as '证书文件', |
|||
pub_key as '公钥文件', |
|||
pub_key_id as '公钥ID', |
|||
status as '状态' |
|||
FROM sys_payment |
|||
WHERE tenant_id = 10547 AND type = 0; -- 请替换为实际的租户ID |
|||
*/ |
|||
|
|||
-- 3. 查找可能导致"Value must not be null!"的问题 |
|||
SELECT |
|||
'=== 潜在问题检查 ===' as section, |
|||
tenant_id, |
|||
CASE |
|||
WHEN mch_id IS NULL THEN '商户号为NULL' |
|||
WHEN mch_id = '' THEN '商户号为空字符串' |
|||
ELSE NULL |
|||
END as mch_id_issue, |
|||
CASE |
|||
WHEN app_id IS NULL THEN '应用ID为NULL' |
|||
WHEN app_id = '' THEN '应用ID为空字符串' |
|||
ELSE NULL |
|||
END as app_id_issue, |
|||
CASE |
|||
WHEN merchant_serial_number IS NULL THEN '证书序列号为NULL' |
|||
WHEN merchant_serial_number = '' THEN '证书序列号为空字符串' |
|||
ELSE NULL |
|||
END as serial_number_issue, |
|||
CASE |
|||
WHEN api_key IS NULL THEN 'API密钥为NULL' |
|||
WHEN api_key = '' THEN 'API密钥为空字符串' |
|||
WHEN LENGTH(api_key) != 32 THEN CONCAT('API密钥长度错误(', LENGTH(api_key), ')') |
|||
ELSE NULL |
|||
END as api_key_issue |
|||
FROM sys_payment |
|||
WHERE type = 0 |
|||
HAVING mch_id_issue IS NOT NULL |
|||
OR app_id_issue IS NOT NULL |
|||
OR serial_number_issue IS NOT NULL |
|||
OR api_key_issue IS NOT NULL; |
|||
|
|||
-- 4. 生成修复建议 |
|||
SELECT |
|||
'=== 修复建议 ===' as section, |
|||
tenant_id, |
|||
CONCAT( |
|||
'-- 租户 ', tenant_id, ' 的修复SQL:\n', |
|||
'UPDATE sys_payment SET \n', |
|||
CASE WHEN mch_id IS NULL OR mch_id = '' THEN ' mch_id = ''YOUR_MERCHANT_ID'',\n' ELSE '' END, |
|||
CASE WHEN app_id IS NULL OR app_id = '' THEN ' app_id = ''YOUR_APP_ID'',\n' ELSE '' END, |
|||
CASE WHEN merchant_serial_number IS NULL OR merchant_serial_number = '' THEN ' merchant_serial_number = ''YOUR_SERIAL_NUMBER'',\n' ELSE '' END, |
|||
CASE WHEN api_key IS NULL OR api_key = '' THEN ' api_key = ''YOUR_32_CHAR_API_KEY'',\n' ELSE '' END, |
|||
' status = 1\n', |
|||
'WHERE tenant_id = ', tenant_id, ' AND type = 0;\n' |
|||
) as fix_sql |
|||
FROM sys_payment |
|||
WHERE type = 0 |
|||
AND (mch_id IS NULL OR mch_id = '' |
|||
OR app_id IS NULL OR app_id = '' |
|||
OR merchant_serial_number IS NULL OR merchant_serial_number = '' |
|||
OR api_key IS NULL OR api_key = ''); |
|||
|
|||
-- 5. 检查证书文件路径配置 |
|||
SELECT |
|||
'=== 证书文件路径检查 ===' as section, |
|||
tenant_id, |
|||
apiclient_key as '私钥文件路径', |
|||
apiclient_cert as '证书文件路径', |
|||
pub_key as '公钥文件路径', |
|||
CASE |
|||
WHEN apiclient_key IS NOT NULL AND apiclient_key != '' |
|||
THEN '✅ 私钥路径已配置' |
|||
ELSE '❌ 私钥路径未配置' |
|||
END as private_key_status, |
|||
CASE |
|||
WHEN pub_key IS NOT NULL AND pub_key != '' |
|||
THEN '✅ 公钥路径已配置' |
|||
ELSE '⚠️ 公钥路径未配置(将使用自动证书)' |
|||
END as public_key_status |
|||
FROM sys_payment |
|||
WHERE type = 0 |
|||
ORDER BY tenant_id; |
@ -0,0 +1,33 @@ |
|||
-- 快速支付配置检查SQL |
|||
-- 请在数据库中执行此查询 |
|||
|
|||
SELECT |
|||
'=== 支付配置检查 ===' as title, |
|||
tenant_id as '租户ID', |
|||
CASE |
|||
WHEN mch_id IS NULL OR mch_id = '' THEN '❌ 未配置' |
|||
ELSE CONCAT('✅ ', mch_id) |
|||
END as '商户号', |
|||
CASE |
|||
WHEN app_id IS NULL OR app_id = '' THEN '❌ 未配置' |
|||
ELSE CONCAT('✅ ', app_id) |
|||
END as '应用ID', |
|||
CASE |
|||
WHEN merchant_serial_number IS NULL OR merchant_serial_number = '' THEN '❌ 未配置' |
|||
ELSE '✅ 已配置' |
|||
END as '证书序列号', |
|||
CASE |
|||
WHEN api_key IS NULL OR api_key = '' THEN '❌ 未配置' |
|||
WHEN LENGTH(api_key) != 32 THEN CONCAT('❌ 长度错误(', LENGTH(api_key), '位)') |
|||
ELSE '✅ 已配置(32位)' |
|||
END as 'API密钥', |
|||
CASE |
|||
WHEN status = 1 THEN '✅ 已启用' |
|||
ELSE '❌ 未启用' |
|||
END as '状态' |
|||
FROM sys_payment |
|||
WHERE type = 0 -- 微信支付 |
|||
ORDER BY tenant_id; |
|||
|
|||
-- 如果上面的查询没有返回结果,说明没有微信支付配置,请执行: |
|||
-- SELECT COUNT(*) as '微信支付配置数量' FROM sys_payment WHERE type = 0; |
@ -0,0 +1,302 @@ |
|||
package com.gxwebsoft.common.core.controller; |
|||
|
|||
import com.gxwebsoft.common.core.service.PaymentCacheService; |
|||
import com.gxwebsoft.common.system.entity.Payment; |
|||
import com.gxwebsoft.common.system.service.PaymentService; |
|||
import com.gxwebsoft.common.system.param.PaymentParam; |
|||
import com.gxwebsoft.common.core.web.ApiResult; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.PathVariable; |
|||
|
|||
import com.gxwebsoft.common.core.web.ApiResult; |
|||
import com.gxwebsoft.common.core.web.BaseController; |
|||
import io.swagger.v3.oas.annotations.Operation; |
|||
import io.swagger.v3.oas.annotations.tags.Tag; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import java.time.LocalDateTime; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* 测试控制器 |
|||
* 用于测试LocalDateTime序列化 |
|||
* |
|||
* @author WebSoft |
|||
* @since 2025-01-12 |
|||
*/ |
|||
@Tag(name = "测试接口") |
|||
@RestController |
|||
@RequestMapping("/api/test") |
|||
public class TestController extends BaseController { |
|||
|
|||
@Autowired |
|||
private PaymentCacheService paymentCacheService; |
|||
|
|||
@Autowired |
|||
private PaymentService paymentService; |
|||
|
|||
@Operation(summary = "测试LocalDateTime序列化") |
|||
@GetMapping("/datetime") |
|||
public ApiResult<Map<String, Object>> testDateTime() { |
|||
Map<String, Object> result = new HashMap<>(); |
|||
// 使用字符串格式避免序列化问题
|
|||
result.put("currentTime", LocalDateTime.now().toString()); |
|||
result.put("currentTimeFormatted", LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); |
|||
result.put("message", "LocalDateTime序列化测试"); |
|||
result.put("timestamp", System.currentTimeMillis()); |
|||
return success(result); |
|||
} |
|||
|
|||
@Operation(summary = "基础诊断 - 不依赖支付服务") |
|||
@GetMapping("/basic-debug/{tenantId}") |
|||
public ApiResult<String> basicDebug(@PathVariable Integer tenantId) { |
|||
try { |
|||
System.out.println("=== 基础诊断开始 ==="); |
|||
System.out.println("接收到的租户ID: " + tenantId); |
|||
|
|||
if (tenantId == null) { |
|||
return fail("租户ID为null",null); |
|||
} |
|||
|
|||
return success("基础诊断通过,租户ID: " + tenantId,null); |
|||
|
|||
} catch (Exception e) { |
|||
System.err.println("基础诊断异常: " + e.getMessage()); |
|||
e.printStackTrace(); |
|||
return fail("基础诊断异常: " + e.getMessage(),null); |
|||
} |
|||
} |
|||
|
|||
@Operation(summary = "快速诊断支付配置") |
|||
@GetMapping("/payment-debug/{tenantId}") |
|||
public ApiResult<String> debugPaymentConfig(@PathVariable Integer tenantId) { |
|||
try { |
|||
System.out.println("=== 开始诊断租户 " + tenantId + " 的支付配置 ==="); |
|||
|
|||
// 检查基础参数
|
|||
if (tenantId == null) { |
|||
return fail("租户ID为null",null); |
|||
} |
|||
|
|||
// 检查服务是否可用
|
|||
if (paymentCacheService == null) { |
|||
return fail("PaymentCacheService未注入",null); |
|||
} |
|||
|
|||
System.out.println("准备调用 paymentCacheService.getWechatPayConfig(" + tenantId + ")"); |
|||
|
|||
// 获取支付配置
|
|||
Payment payment = null; |
|||
try { |
|||
payment = paymentCacheService.getWechatPayConfig(tenantId); |
|||
System.out.println("成功调用 getWechatPayConfig,结果: " + (payment != null ? "非null" : "null")); |
|||
} catch (Exception e) { |
|||
System.err.println("调用 getWechatPayConfig 异常: " + e.getMessage()); |
|||
e.printStackTrace(); |
|||
return fail("获取支付配置异常: " + e.getMessage() + " (类型: " + e.getClass().getName() + ")",null); |
|||
} |
|||
|
|||
if (payment == null) { |
|||
System.out.println("❌ 支付配置不存在"); |
|||
return fail("支付配置不存在,租户ID: " + tenantId,null); |
|||
} |
|||
|
|||
// 构建诊断信息字符串,避免序列化问题
|
|||
StringBuilder diagnosis = new StringBuilder(); |
|||
diagnosis.append("=== 支付配置诊断结果 ===\n"); |
|||
diagnosis.append("租户ID: ").append(tenantId).append("\n"); |
|||
diagnosis.append("商户号: ").append(payment.getMchId()).append("\n"); |
|||
diagnosis.append("应用ID: ").append(payment.getAppId()).append("\n"); |
|||
diagnosis.append("证书序列号: ").append(payment.getMerchantSerialNumber()).append("\n"); |
|||
diagnosis.append("API密钥: ").append(payment.getApiKey() != null ? "已配置(长度:" + payment.getApiKey().length() + ")" : "未配置").append("\n"); |
|||
diagnosis.append("状态: ").append(payment.getStatus()).append("\n"); |
|||
diagnosis.append("私钥文件: ").append(payment.getApiclientKey()).append("\n"); |
|||
diagnosis.append("证书文件: ").append(payment.getApiclientCert()).append("\n"); |
|||
diagnosis.append("公钥文件: ").append(payment.getPubKey()).append("\n"); |
|||
diagnosis.append("公钥ID: ").append(payment.getPubKeyId()).append("\n"); |
|||
|
|||
// 检查问题
|
|||
StringBuilder issues = new StringBuilder(); |
|||
if (payment.getMchId() == null || payment.getMchId().trim().isEmpty()) { |
|||
issues.append("❌ 商户号为空\n"); |
|||
} |
|||
if (payment.getAppId() == null || payment.getAppId().trim().isEmpty()) { |
|||
issues.append("❌ 应用ID为空\n"); |
|||
} |
|||
if (payment.getMerchantSerialNumber() == null || payment.getMerchantSerialNumber().trim().isEmpty()) { |
|||
issues.append("❌ 证书序列号为空\n"); |
|||
} |
|||
if (payment.getApiKey() == null || payment.getApiKey().trim().isEmpty()) { |
|||
issues.append("❌ API密钥为空\n"); |
|||
} else if (payment.getApiKey().length() != 32) { |
|||
issues.append("❌ API密钥长度错误(").append(payment.getApiKey().length()).append("位)\n"); |
|||
} |
|||
if (payment.getStatus() == null || !payment.getStatus()) { |
|||
issues.append("❌ 支付配置未启用\n"); |
|||
} |
|||
|
|||
if (issues.length() > 0) { |
|||
diagnosis.append("\n=== 发现的问题 ===\n"); |
|||
diagnosis.append(issues.toString()); |
|||
} else { |
|||
diagnosis.append("\n✅ 配置检查通过,无问题发现"); |
|||
} |
|||
|
|||
// 打印到控制台
|
|||
System.out.println(diagnosis.toString()); |
|||
|
|||
if (issues.length() > 0) { |
|||
return fail(diagnosis.toString(),null); |
|||
} else { |
|||
return success(diagnosis.toString(),null); |
|||
} |
|||
|
|||
} catch (Exception e) { |
|||
String errorMsg = "诊断失败: " + e.getMessage() + " (类型: " + e.getClass().getName() + ")"; |
|||
System.err.println(errorMsg); |
|||
e.printStackTrace(); |
|||
return fail(errorMsg,null); |
|||
} |
|||
} |
|||
|
|||
@Operation(summary = "直接数据库查询支付配置") |
|||
@GetMapping("/db-payment-check/{tenantId}") |
|||
public ApiResult<String> checkPaymentFromDB(@PathVariable Integer tenantId) { |
|||
try { |
|||
System.out.println("=== 直接数据库查询支付配置 ==="); |
|||
System.out.println("租户ID: " + tenantId); |
|||
|
|||
if (tenantId == null) { |
|||
return fail("租户ID为null",null); |
|||
} |
|||
|
|||
if (paymentService == null) { |
|||
return fail("PaymentService未注入",null); |
|||
} |
|||
|
|||
// 直接查询数据库,不使用缓存
|
|||
PaymentParam param = new PaymentParam(); |
|||
param.setType(0); // 微信支付
|
|||
param.setTenantId(tenantId); |
|||
|
|||
System.out.println("准备查询数据库,参数: type=0, tenantId=" + tenantId); |
|||
|
|||
java.util.List<Payment> payments = paymentService.listRel(param); |
|||
|
|||
System.out.println("查询结果数量: " + (payments != null ? payments.size() : "null")); |
|||
|
|||
if (payments == null || payments.isEmpty()) { |
|||
return fail("数据库中没有找到租户 " + tenantId + " 的微信支付配置",null); |
|||
} |
|||
|
|||
Payment payment = payments.get(0); |
|||
|
|||
StringBuilder result = new StringBuilder(); |
|||
result.append("=== 数据库查询结果 ===\n"); |
|||
result.append("租户ID: ").append(payment.getTenantId()).append("\n"); |
|||
result.append("支付方式: ").append(payment.getName()).append("\n"); |
|||
result.append("类型: ").append(payment.getType()).append("\n"); |
|||
result.append("商户号: ").append(payment.getMchId()).append("\n"); |
|||
result.append("应用ID: ").append(payment.getAppId()).append("\n"); |
|||
result.append("证书序列号: ").append(payment.getMerchantSerialNumber()).append("\n"); |
|||
result.append("API密钥状态: ").append(payment.getApiKey() != null ? "已配置(长度:" + payment.getApiKey().length() + ")" : "未配置").append("\n"); |
|||
result.append("状态: ").append(payment.getStatus()).append("\n"); |
|||
result.append("是否删除: ").append(payment.getDeleted()).append("\n"); |
|||
|
|||
System.out.println(result.toString()); |
|||
|
|||
return success(result.toString(),null); |
|||
|
|||
} catch (Exception e) { |
|||
String errorMsg = "数据库查询异常: " + e.getMessage() + " (类型: " + e.getClass().getName() + ")"; |
|||
System.err.println(errorMsg); |
|||
e.printStackTrace(); |
|||
return fail(errorMsg,null); |
|||
} |
|||
} |
|||
|
|||
@Operation(summary = "清理支付配置缓存") |
|||
@GetMapping("/clear-payment-cache/{tenantId}") |
|||
public String clearPaymentCache(@PathVariable Integer tenantId) { |
|||
try { |
|||
System.out.println("=== 清理支付配置缓存 ==="); |
|||
System.out.println("租户ID: " + tenantId); |
|||
|
|||
if (tenantId == null) { |
|||
return "错误: 租户ID为null"; |
|||
} |
|||
|
|||
// 清理可能的缓存键
|
|||
paymentCacheService.removePaymentConfig("0", tenantId); // 微信支付
|
|||
paymentCacheService.removePaymentConfig("wechat", tenantId); // 可能的其他格式
|
|||
|
|||
String result = "✅ 缓存已清理,租户ID: " + tenantId; |
|||
System.out.println(result); |
|||
return result; |
|||
|
|||
} catch (Exception e) { |
|||
String errorMsg = "❌ 清理缓存异常: " + e.getMessage(); |
|||
System.err.println(errorMsg); |
|||
e.printStackTrace(); |
|||
return errorMsg; |
|||
} |
|||
} |
|||
|
|||
@Operation(summary = "最简单的测试接口") |
|||
@GetMapping("/simple-test") |
|||
public String simpleTest() { |
|||
return "✅ 测试接口正常工作,时间: " + System.currentTimeMillis(); |
|||
} |
|||
|
|||
@Operation(summary = "测试支付配置是否存在") |
|||
@GetMapping("/check-payment-exists/{tenantId}") |
|||
public String checkPaymentExists(@PathVariable Integer tenantId) { |
|||
try { |
|||
System.out.println("=== 检查支付配置是否存在 ==="); |
|||
System.out.println("租户ID: " + tenantId); |
|||
|
|||
if (tenantId == null) { |
|||
return "❌ 租户ID为null"; |
|||
} |
|||
|
|||
if (paymentService == null) { |
|||
return "❌ PaymentService未注入"; |
|||
} |
|||
|
|||
// 使用最简单的查询
|
|||
PaymentParam param = new PaymentParam(); |
|||
param.setType(0); |
|||
param.setTenantId(tenantId); |
|||
|
|||
java.util.List<Payment> payments = paymentService.listRel(param); |
|||
|
|||
if (payments == null) { |
|||
return "❌ 查询结果为null"; |
|||
} |
|||
|
|||
if (payments.isEmpty()) { |
|||
return "❌ 没有找到支付配置,租户ID: " + tenantId; |
|||
} |
|||
|
|||
Payment payment = payments.get(0); |
|||
StringBuilder result = new StringBuilder(); |
|||
result.append("✅ 找到支付配置\n"); |
|||
result.append("租户ID: ").append(payment.getTenantId()).append("\n"); |
|||
result.append("商户号: ").append(payment.getMchId() != null ? payment.getMchId() : "NULL").append("\n"); |
|||
result.append("应用ID: ").append(payment.getAppId() != null ? payment.getAppId() : "NULL").append("\n"); |
|||
result.append("状态: ").append(payment.getStatus()).append("\n"); |
|||
|
|||
return result.toString(); |
|||
|
|||
} catch (Exception e) { |
|||
String error = "❌ 检查异常: " + e.getMessage(); |
|||
System.err.println(error); |
|||
e.printStackTrace(); |
|||
return error; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,211 @@ |
|||
package com.gxwebsoft.common.core.controller; |
|||
|
|||
import com.gxwebsoft.common.core.utils.WechatCertAutoConfig; |
|||
import com.gxwebsoft.common.core.web.ApiResult; |
|||
import com.gxwebsoft.common.core.web.BaseController; |
|||
import com.wechat.pay.java.core.Config; |
|||
import io.swagger.v3.oas.annotations.Operation; |
|||
import io.swagger.v3.oas.annotations.Parameter; |
|||
import io.swagger.v3.oas.annotations.tags.Tag; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* 微信支付证书自动配置测试控制器 |
|||
* |
|||
* @author 科技小王子 |
|||
* @since 2024-07-26 |
|||
*/ |
|||
@Slf4j |
|||
@RestController |
|||
@RequestMapping("/api/wechat-cert-test") |
|||
@Tag(name = "微信支付证书自动配置测试") |
|||
public class WechatCertTestController extends BaseController { |
|||
|
|||
@Autowired |
|||
private WechatCertAutoConfig wechatCertAutoConfig; |
|||
|
|||
@Operation(summary = "测试默认开发环境证书配置") |
|||
@PostMapping("/test-default") |
|||
public ApiResult<Map<String, Object>> testDefaultConfig() { |
|||
Map<String, Object> result = new HashMap<>(); |
|||
|
|||
try { |
|||
log.info("开始测试默认开发环境证书配置..."); |
|||
|
|||
// 创建自动证书配置
|
|||
Config config = wechatCertAutoConfig.createDefaultDevConfig(); |
|||
|
|||
// 测试配置
|
|||
boolean testResult = wechatCertAutoConfig.testConfig(config); |
|||
|
|||
result.put("success", true); |
|||
result.put("configCreated", config != null); |
|||
result.put("testPassed", testResult); |
|||
result.put("message", "默认证书配置测试完成"); |
|||
result.put("instructions", wechatCertAutoConfig.getUsageInstructions()); |
|||
|
|||
log.info("✅ 默认证书配置测试成功"); |
|||
return success("测试成功", result); |
|||
|
|||
} catch (Exception e) { |
|||
log.error("❌ 默认证书配置测试失败: {}", e.getMessage(), e); |
|||
|
|||
result.put("success", false); |
|||
result.put("error", e.getMessage()); |
|||
result.put("message", "证书配置测试失败"); |
|||
result.put("troubleshooting", getTroubleshootingInfo()); |
|||
|
|||
return fail("测试失败: " + e.getMessage(), result); |
|||
} |
|||
} |
|||
|
|||
@Operation(summary = "测试自定义证书配置") |
|||
@PostMapping("/test-custom") |
|||
public ApiResult<Map<String, Object>> testCustomConfig( |
|||
@Parameter(description = "商户号") @RequestParam String merchantId, |
|||
@Parameter(description = "私钥文件路径") @RequestParam String privateKeyPath, |
|||
@Parameter(description = "证书序列号") @RequestParam String merchantSerialNumber, |
|||
@Parameter(description = "APIv3密钥") @RequestParam String apiV3Key) { |
|||
|
|||
Map<String, Object> result = new HashMap<>(); |
|||
|
|||
try { |
|||
log.info("开始测试自定义证书配置..."); |
|||
log.info("商户号: {}", merchantId); |
|||
log.info("私钥路径: {}", privateKeyPath); |
|||
|
|||
// 创建自动证书配置
|
|||
Config config = wechatCertAutoConfig.createAutoConfig( |
|||
merchantId, privateKeyPath, merchantSerialNumber, apiV3Key); |
|||
|
|||
// 测试配置
|
|||
boolean testResult = wechatCertAutoConfig.testConfig(config); |
|||
|
|||
result.put("success", true); |
|||
result.put("configCreated", config != null); |
|||
result.put("testPassed", testResult); |
|||
result.put("message", "自定义证书配置测试完成"); |
|||
result.put("merchantId", merchantId); |
|||
result.put("privateKeyPath", privateKeyPath); |
|||
|
|||
log.info("✅ 自定义证书配置测试成功"); |
|||
return success("测试成功", result); |
|||
|
|||
} catch (Exception e) { |
|||
log.error("❌ 自定义证书配置测试失败: {}", e.getMessage(), e); |
|||
|
|||
result.put("success", false); |
|||
result.put("error", e.getMessage()); |
|||
result.put("message", "证书配置测试失败"); |
|||
result.put("troubleshooting", getTroubleshootingInfo()); |
|||
|
|||
return fail("测试失败: " + e.getMessage(), result); |
|||
} |
|||
} |
|||
|
|||
@Operation(summary = "获取使用说明") |
|||
@GetMapping("/instructions") |
|||
public ApiResult<String> getInstructions() { |
|||
String instructions = wechatCertAutoConfig.getUsageInstructions(); |
|||
return success("获取使用说明成功", instructions); |
|||
} |
|||
|
|||
@Operation(summary = "获取故障排除信息") |
|||
@GetMapping("/troubleshooting") |
|||
public ApiResult<Map<String, Object>> getTroubleshooting() { |
|||
Map<String, Object> troubleshooting = getTroubleshootingInfo(); |
|||
return success("获取故障排除信息成功", troubleshooting); |
|||
} |
|||
|
|||
/** |
|||
* 获取故障排除信息 |
|||
*/ |
|||
private Map<String, Object> getTroubleshootingInfo() { |
|||
Map<String, Object> info = new HashMap<>(); |
|||
|
|||
info.put("commonIssues", Map.of( |
|||
"404错误", "商户平台未开启API安全功能或未申请使用微信支付公钥", |
|||
"证书序列号错误", "请检查商户平台中的证书序列号是否正确", |
|||
"APIv3密钥错误", "请确认APIv3密钥是否正确设置", |
|||
"私钥文件不存在", "请检查私钥文件路径是否正确", |
|||
"网络连接问题", "请检查网络连接是否正常" |
|||
)); |
|||
|
|||
info.put("solutions", Map.of( |
|||
"开启API安全", "登录微信商户平台 -> 账户中心 -> API安全 -> 申请使用微信支付公钥", |
|||
"获取证书序列号", "在API安全页面查看或重新下载证书", |
|||
"设置APIv3密钥", "在API安全页面设置APIv3密钥", |
|||
"检查私钥文件", "确保apiclient_key.pem文件存在且路径正确" |
|||
)); |
|||
|
|||
info.put("advantages", Map.of( |
|||
"自动下载", "RSAAutoCertificateConfig会自动下载平台证书", |
|||
"自动更新", "证书过期时会自动更新", |
|||
"简化管理", "无需手动管理wechatpay_cert.pem文件", |
|||
"官方推荐", "微信支付官方推荐的证书管理方式" |
|||
)); |
|||
|
|||
info.put("documentation", "https://pay.weixin.qq.com/doc/v3/merchant/4012153196"); |
|||
|
|||
return info; |
|||
} |
|||
|
|||
@Operation(summary = "检查商户平台配置状态") |
|||
@PostMapping("/check-merchant-config") |
|||
public ApiResult<Map<String, Object>> checkMerchantConfig( |
|||
@RequestParam String merchantId, |
|||
@RequestParam String privateKeyPath, |
|||
@RequestParam String merchantSerialNumber, |
|||
@RequestParam String apiV3Key) { |
|||
|
|||
Map<String, Object> result = new HashMap<>(); |
|||
|
|||
try { |
|||
log.info("开始检查商户平台配置状态..."); |
|||
log.info("商户号: {}", merchantId); |
|||
|
|||
// 尝试创建自动证书配置
|
|||
Config config = wechatCertAutoConfig.createAutoConfig( |
|||
merchantId, privateKeyPath, merchantSerialNumber, apiV3Key); |
|||
|
|||
result.put("success", true); |
|||
result.put("configCreated", true); |
|||
result.put("message", "商户平台配置正常,自动证书配置创建成功"); |
|||
result.put("merchantId", merchantId); |
|||
result.put("recommendation", "配置正常,可以正常使用微信支付功能"); |
|||
|
|||
log.info("✅ 商户平台配置检查成功"); |
|||
return success("配置检查成功", result); |
|||
|
|||
} catch (Exception e) { |
|||
log.error("❌ 商户平台配置检查失败: {}", e.getMessage(), e); |
|||
|
|||
result.put("success", false); |
|||
result.put("configCreated", false); |
|||
result.put("error", e.getMessage()); |
|||
result.put("merchantId", merchantId); |
|||
|
|||
// 分析错误类型并提供解决方案
|
|||
if (e.getMessage().contains("404") || e.getMessage().contains("RESOURCE_NOT_EXISTS")) { |
|||
result.put("errorType", "商户平台配置问题"); |
|||
result.put("solution", "请在微信支付商户平台完成以下配置:\n" + |
|||
"1. 登录商户平台:https://pay.weixin.qq.com/\n" + |
|||
"2. 进入:产品中心 → 开发配置 → API安全\n" + |
|||
"3. 申请API证书\n" + |
|||
"4. 申请使用微信支付公钥\n" + |
|||
"5. 确保API证书和微信支付公钥状态为\"已生效\""); |
|||
result.put("documentUrl", "https://pay.weixin.qq.com/doc/v3/merchant/4012153196"); |
|||
} else { |
|||
result.put("errorType", "其他配置问题"); |
|||
result.put("solution", "请检查商户号、证书序列号、API密钥等配置是否正确"); |
|||
} |
|||
|
|||
return success("配置检查完成(发现问题)", result); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,39 @@ |
|||
package com.gxwebsoft.common.system.dto; |
|||
|
|||
import lombok.Data; |
|||
import java.io.Serializable; |
|||
|
|||
/** |
|||
* 支付配置缓存DTO |
|||
* 专门用于Redis缓存,不包含时间字段,避免序列化问题 |
|||
* |
|||
* @author 科技小王子 |
|||
* @since 2025-01-13 |
|||
*/ |
|||
@Data |
|||
public class PaymentCacheDTO implements Serializable { |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
private Integer id; |
|||
private String name; |
|||
private Integer type; |
|||
private String code; |
|||
private String image; |
|||
private Integer wechatType; |
|||
private String appId; |
|||
private String mchId; |
|||
private String apiKey; |
|||
private String apiclientCert; |
|||
private String apiclientKey; |
|||
private String pubKey; |
|||
private String pubKeyId; |
|||
private String merchantSerialNumber; |
|||
private String notifyUrl; |
|||
private String comments; |
|||
private Integer sortNumber; |
|||
private Boolean status; |
|||
private Integer deleted; |
|||
private Integer tenantId; |
|||
|
|||
// 不包含 createTime 和 updateTime 字段,避免序列化问题
|
|||
} |
Loading…
Reference in new issue