diff --git a/src/main/java/com/gxwebsoft/common/core/controller/PaymentConfigController.java b/src/main/java/com/gxwebsoft/common/core/controller/PaymentConfigController.java new file mode 100644 index 0000000..37706fd --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/controller/PaymentConfigController.java @@ -0,0 +1,149 @@ +package com.gxwebsoft.common.core.controller; + +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.common.system.service.PaymentService; +import com.gxwebsoft.common.core.service.PaymentCacheService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +/** + * 支付配置管理控制器 + * 用于检查和管理支付配置 + * + * @author 科技小王子 + * @since 2025-07-27 + */ +@Slf4j +@Tag(name = "支付配置管理") +@RestController +@RequestMapping("/api/system/payment-config") +public class PaymentConfigController extends BaseController { + + @Autowired + private PaymentService paymentService; + + @Autowired + private PaymentCacheService paymentCacheService; + + @Operation(summary = "检查支付配置") + @GetMapping("/check/{payType}") + @PreAuthorize("hasAuthority('sys:payment:list')") + public ApiResult> checkPaymentConfig(@PathVariable Integer payType) { + try { + Map result = new HashMap<>(); + + // 获取支付配置 + Payment payment = paymentCacheService.getPaymentConfig(payType, getTenantId()); + + if (payment == null) { + result.put("status", "error"); + result.put("message", "未找到支付配置"); + return success("检查完成", result); + } + + // 检查配置完整性 + Map configCheck = new HashMap<>(); + configCheck.put("id", payment.getId()); + configCheck.put("name", payment.getName()); + configCheck.put("type", payment.getType()); + configCheck.put("code", payment.getCode()); + configCheck.put("appId", payment.getAppId()); + configCheck.put("mchId", payment.getMchId()); + configCheck.put("apiKeyConfigured", payment.getApiKey() != null && !payment.getApiKey().trim().isEmpty()); + configCheck.put("apiKeyLength", payment.getApiKey() != null ? payment.getApiKey().length() : 0); + configCheck.put("merchantSerialNumber", payment.getMerchantSerialNumber()); + configCheck.put("status", payment.getStatus()); + configCheck.put("tenantId", payment.getTenantId()); + + // 检查必要字段 + boolean isValid = true; + StringBuilder errors = new StringBuilder(); + + if (payment.getMchId() == null || payment.getMchId().trim().isEmpty()) { + isValid = false; + errors.append("商户号(mchId)未配置; "); + } + + if (payment.getApiKey() == null || payment.getApiKey().trim().isEmpty()) { + isValid = false; + errors.append("API密钥(apiKey)未配置; "); + } + + if (payment.getMerchantSerialNumber() == null || payment.getMerchantSerialNumber().trim().isEmpty()) { + isValid = false; + errors.append("商户证书序列号(merchantSerialNumber)未配置; "); + } + + if (payment.getAppId() == null || payment.getAppId().trim().isEmpty()) { + isValid = false; + errors.append("应用ID(appId)未配置; "); + } + + result.put("status", isValid ? "success" : "error"); + result.put("valid", isValid); + result.put("errors", errors.toString()); + result.put("config", configCheck); + + return success("检查完成", result); + + } catch (Exception e) { + log.error("检查支付配置失败", e); + Map result = new HashMap<>(); + result.put("status", "error"); + result.put("message", "检查失败: " + e.getMessage()); + return success("检查完成", result); + } + } + + @Operation(summary = "初始化微信支付配置") + @PostMapping("/init-wechat") + @PreAuthorize("hasAuthority('sys:payment:save')") + public ApiResult initWechatPayConfig(@RequestBody Map config) { + try { + Payment payment = new Payment(); + payment.setName("微信支付"); + payment.setType(0); // 微信支付类型为0 + payment.setCode("0"); + payment.setAppId(config.get("appId")); + payment.setMchId(config.get("mchId")); + payment.setApiKey(config.get("apiKey")); + payment.setMerchantSerialNumber(config.get("merchantSerialNumber")); + payment.setStatus(true); + payment.setTenantId(getTenantId()); + + if (paymentService.save(payment)) { + // 缓存配置 + paymentCacheService.cachePaymentConfig(payment, getTenantId()); + return success("微信支付配置初始化成功"); + } else { + return fail("微信支付配置初始化失败"); + } + + } catch (Exception e) { + log.error("初始化微信支付配置失败", e); + return fail("初始化失败: " + e.getMessage()); + } + } + + @Operation(summary = "清除支付配置缓存") + @DeleteMapping("/cache/{payType}") + @PreAuthorize("hasAuthority('sys:payment:update')") + public ApiResult clearPaymentCache(@PathVariable Integer payType) { + try { + paymentCacheService.removePaymentConfig(payType.toString(), getTenantId()); + return success("缓存清除成功"); + } catch (Exception e) { + log.error("清除支付配置缓存失败", e); + return fail("清除缓存失败: " + e.getMessage()); + } + } +} diff --git a/src/main/resources/sql/check_payment_config.sql b/src/main/resources/sql/check_payment_config.sql new file mode 100644 index 0000000..68f0e82 --- /dev/null +++ b/src/main/resources/sql/check_payment_config.sql @@ -0,0 +1,91 @@ +-- 检查支付配置的SQL脚本 + +-- 1. 查看所有支付配置 +SELECT + id, + name, + type, + code, + app_id, + mch_id, + CASE + WHEN api_key IS NULL OR api_key = '' THEN '未配置' + ELSE CONCAT('已配置(长度:', LENGTH(api_key), ')') + END as api_key_status, + merchant_serial_number, + status, + tenant_id, + create_time +FROM sys_payment +ORDER BY type, tenant_id; + +-- 2. 检查微信支付配置(type=0) +SELECT + id, + name, + app_id, + mch_id, + CASE + WHEN api_key IS NULL OR api_key = '' THEN 'ERROR: API密钥未配置' + WHEN LENGTH(api_key) < 32 THEN 'WARNING: API密钥长度可能不正确' + ELSE 'OK' + END as api_key_check, + CASE + WHEN merchant_serial_number IS NULL OR merchant_serial_number = '' THEN 'ERROR: 序列号未配置' + WHEN LENGTH(merchant_serial_number) != 40 THEN 'WARNING: 序列号长度可能不正确' + ELSE 'OK' + END as serial_number_check, + CASE + WHEN mch_id IS NULL OR mch_id = '' THEN 'ERROR: 商户号未配置' + ELSE 'OK' + END as mch_id_check, + CASE + WHEN app_id IS NULL OR app_id = '' THEN 'ERROR: 应用ID未配置' + ELSE 'OK' + END as app_id_check, + status, + tenant_id +FROM sys_payment +WHERE type = 0 +ORDER BY tenant_id; + +-- 3. 插入示例微信支付配置(请根据实际情况修改) +-- 注意:请将下面的值替换为您的实际配置 +/* +INSERT INTO sys_payment ( + name, + type, + code, + app_id, + mch_id, + api_key, + merchant_serial_number, + status, + tenant_id, + create_time, + update_time +) VALUES ( + '微信支付', + 0, + '0', + 'wx1234567890abcdef', -- 请替换为您的微信小程序AppID + '1723321338', -- 请替换为您的商户号 + 'your_api_v3_key_here', -- 请替换为您的APIv3密钥 + '2B933F7C35014A1C363642623E4A62364B34C4EB', -- 请替换为您的商户证书序列号 + 1, + 10550, -- 请替换为您的租户ID + NOW(), + NOW() +) ON DUPLICATE KEY UPDATE + app_id = VALUES(app_id), + mch_id = VALUES(mch_id), + api_key = VALUES(api_key), + merchant_serial_number = VALUES(merchant_serial_number), + update_time = NOW(); +*/ + +-- 4. 检查特定租户的支付配置 +-- SELECT * FROM sys_payment WHERE tenant_id = 10550 AND type = 0; + +-- 5. 删除错误的支付配置(谨慎使用) +-- DELETE FROM sys_payment WHERE id = ?; diff --git a/src/test/java/com/gxwebsoft/test/CertificateTest.java b/src/test/java/com/gxwebsoft/test/CertificateTest.java new file mode 100644 index 0000000..4a2ed1e --- /dev/null +++ b/src/test/java/com/gxwebsoft/test/CertificateTest.java @@ -0,0 +1,61 @@ +package com.gxwebsoft.test; + +import com.gxwebsoft.common.core.config.CertificateProperties; +import com.gxwebsoft.common.core.utils.CertificateLoader; +import com.gxwebsoft.common.core.utils.WechatCertAutoConfig; +import com.wechat.pay.java.core.Config; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +/** + * 证书测试类 + */ +@SpringBootTest +@ActiveProfiles("dev") +public class CertificateTest { + + @Autowired + private CertificateProperties certConfig; + + @Autowired + private CertificateLoader certificateLoader; + + @Autowired + private WechatCertAutoConfig wechatCertAutoConfig; + + @Test + public void testCertificateLoading() { + try { + System.out.println("=== 证书加载测试 ==="); + + // 测试租户ID + String tenantId = "10550"; + String tenantCertPath = "dev/wechat/" + tenantId; + String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + + System.out.println("证书路径: " + privateKeyPath); + System.out.println("加载模式: " + certConfig.getLoadMode()); + + // 测试证书加载 + String privateKeyFile = certificateLoader.loadCertificatePath(privateKeyPath); + System.out.println("私钥文件路径: " + privateKeyFile); + + // 测试自动证书配置 + System.out.println("=== 测试自动证书配置 ==="); + Config config = wechatCertAutoConfig.createAutoConfig( + "1723321338", // 测试商户号 + privateKeyFile, + "test-serial-number", // 测试序列号 + "test-api-key" // 测试API密钥 + ); + + System.out.println("自动证书配置创建成功: " + (config != null)); + + } catch (Exception e) { + System.err.println("证书测试失败: " + e.getMessage()); + e.printStackTrace(); + } + } +} diff --git a/src/test/java/com/gxwebsoft/test/WechatPayConfigTest.java b/src/test/java/com/gxwebsoft/test/WechatPayConfigTest.java new file mode 100644 index 0000000..3304f88 --- /dev/null +++ b/src/test/java/com/gxwebsoft/test/WechatPayConfigTest.java @@ -0,0 +1,89 @@ +package com.gxwebsoft.test; + +import com.gxwebsoft.common.core.config.CertificateProperties; +import com.gxwebsoft.common.core.utils.CertificateLoader; +import com.gxwebsoft.common.core.utils.WechatCertAutoConfig; +import com.gxwebsoft.common.core.service.PaymentCacheService; +import com.gxwebsoft.common.system.entity.Payment; +import com.wechat.pay.java.core.Config; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +/** + * 微信支付配置测试 + */ +@SpringBootTest +@ActiveProfiles("dev") +public class WechatPayConfigTest { + + @Autowired + private CertificateProperties certConfig; + + @Autowired + private CertificateLoader certificateLoader; + + @Autowired + private WechatCertAutoConfig wechatCertAutoConfig; + + @Autowired + private PaymentCacheService paymentCacheService; + + @Test + public void testWechatPayConfig() { + try { + System.out.println("=== 微信支付配置测试 ==="); + + // 测试租户ID + String tenantId = "10550"; + String tenantCertPath = "dev/wechat/" + tenantId; + String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + + System.out.println("证书路径: " + privateKeyPath); + System.out.println("加载模式: " + certConfig.getLoadMode()); + + // 测试证书加载 + String privateKeyFile = certificateLoader.loadCertificatePath(privateKeyPath); + System.out.println("私钥文件路径: " + privateKeyFile); + + // 测试数据库支付配置 + System.out.println("=== 测试数据库支付配置 ==="); + try { + Payment payment = paymentCacheService.getPaymentConfig(0, 10550); // 微信支付,租户ID 10550 + System.out.println("数据库配置获取成功:"); + System.out.println("商户号: " + payment.getMchId()); + System.out.println("序列号: " + payment.getMerchantSerialNumber()); + System.out.println("API密钥: " + (payment.getApiKey() != null ? "已配置(长度:" + payment.getApiKey().length() + ")" : "未配置")); + System.out.println("应用ID: " + payment.getAppId()); + + // 使用数据库配置进行测试 + if (payment.getMchId() != null && payment.getMerchantSerialNumber() != null && payment.getApiKey() != null) { + Config dbConfig = wechatCertAutoConfig.createAutoConfig( + payment.getMchId(), + privateKeyFile, + payment.getMerchantSerialNumber(), + payment.getApiKey() + ); + System.out.println("使用数据库配置创建成功: " + (dbConfig != null)); + } else { + System.out.println("数据库配置不完整,无法创建微信支付配置"); + } + + } catch (Exception e) { + System.err.println("数据库配置获取失败: " + e.getMessage()); + + // 回退到配置文件参数 + System.out.println("=== 回退到配置文件参数 ==="); + String devApiKey = certConfig.getWechatPay().getDev().getApiV3Key(); + System.out.println("API密钥: " + (devApiKey != null ? "已配置(长度:" + devApiKey.length() + ")" : "未配置")); + } + + System.out.println("=== 测试完成 ==="); + + } catch (Exception e) { + System.err.println("微信支付配置测试失败: " + e.getMessage()); + e.printStackTrace(); + } + } +}