4 changed files with 390 additions and 0 deletions
@ -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<Map<String, Object>> checkPaymentConfig(@PathVariable Integer payType) { |
||||
|
try { |
||||
|
Map<String, Object> result = new HashMap<>(); |
||||
|
|
||||
|
// 获取支付配置
|
||||
|
Payment payment = paymentCacheService.getPaymentConfig(payType, getTenantId()); |
||||
|
|
||||
|
if (payment == null) { |
||||
|
result.put("status", "error"); |
||||
|
result.put("message", "未找到支付配置"); |
||||
|
return success("检查完成", result); |
||||
|
} |
||||
|
|
||||
|
// 检查配置完整性
|
||||
|
Map<String, Object> 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<String, Object> 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<String, String> 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()); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -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 = ?; |
@ -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(); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -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(); |
||||
|
} |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue