package com.gxwebsoft.payment.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.gxwebsoft.common.core.config.CertificateProperties; import com.gxwebsoft.common.core.service.CertificateService; import com.gxwebsoft.common.core.utils.RedisUtil; import com.gxwebsoft.common.core.utils.WxNativeUtil; import com.gxwebsoft.common.system.entity.Payment; import com.gxwebsoft.common.system.param.PaymentParam; import com.gxwebsoft.common.system.service.PaymentService; import com.gxwebsoft.payment.exception.PaymentException; import com.wechat.pay.java.core.Config; import com.wechat.pay.java.core.RSAAutoCertificateConfig; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.io.IOException; import java.util.concurrent.TimeUnit; /** * 微信支付配置服务 * 负责管理微信支付的配置信息和证书 * * @author 科技小王子 * @since 2025-01-26 */ @Slf4j @Service public class WxPayConfigService { @Resource private RedisUtil redisUtil; @Resource private CertificateService certificateService; @Resource private CertificateProperties certificateProperties; @Resource private PaymentService paymentService; @Value("${spring.profiles.active:dev}") private String activeProfile; /** * 获取支付配置信息(Payment对象)- 公开方法 * * @param tenantId 租户ID * @return 支付配置信息 * @throws PaymentException 配置获取失败时抛出 */ public Payment getPaymentConfigForStrategy(Integer tenantId) throws PaymentException { if (tenantId == null) { throw PaymentException.paramError("租户ID不能为空"); } return getPaymentConfig(tenantId); } /** * 获取微信支付配置 * * @param tenantId 租户ID * @return 微信支付配置 * @throws PaymentException 配置获取失败时抛出 */ public Config getWxPayConfig(Integer tenantId) throws PaymentException { if (tenantId == null) { throw PaymentException.paramError("租户ID不能为空"); } // 先从缓存获取已构建的配置 Config cachedConfig = WxNativeUtil.getConfig(tenantId); if (cachedConfig != null) { log.debug("从缓存获取微信支付配置成功,租户ID: {}", tenantId); return cachedConfig; } // 构建新的配置 Config newConfig = buildWxPayConfig(tenantId); // 缓存配置 WxNativeUtil.addConfig(tenantId, newConfig); log.info("微信支付配置创建并缓存成功,租户ID: {}", tenantId); return newConfig; } /** * 构建微信支付配置 */ private Config buildWxPayConfig(Integer tenantId) throws PaymentException { try { // 获取支付配置信息 Payment payment = getPaymentConfig(tenantId); // 获取证书文件路径 String certificatePath = getCertificatePath(tenantId, payment); // 创建微信支付配置对象 return createWxPayConfig(payment, certificatePath); } catch (Exception e) { if (e instanceof PaymentException) { throw e; } throw PaymentException.systemError("构建微信支付配置失败: " + e.getMessage(), e); } } /** * 获取支付配置信息 * 优先从缓存获取,缓存没有则查询数据库,最后兜底到开发环境测试配置 */ private Payment getPaymentConfig(Integer tenantId) throws PaymentException { String cacheKey = "Payment:wxPay:" + tenantId; Payment payment = redisUtil.get(cacheKey, Payment.class); System.out.println("payment = " + payment); if (payment != null) { log.debug("从缓存获取支付配置成功,租户ID: {}", tenantId); // return payment; } // 缓存中没有,尝试从数据库查询 try { final PaymentParam paymentParam = new PaymentParam(); paymentParam.setType(102); paymentParam.setTenantId(tenantId); log.debug("查询数据库支付配置,参数: type=102, tenantId={}", tenantId); payment = paymentService.getByType(paymentParam); log.debug("数据库查询结果: {}", payment != null ? "找到配置" : "未找到配置"); if (payment != null) { log.info("从数据库获取支付配置成功,租户ID: {},将缓存配置", tenantId); // 将查询到的配置缓存起来,缓存1天 redisUtil.set(cacheKey, payment, 1L, TimeUnit.DAYS); return payment; } else { log.warn("数据库中未找到支付配置,租户ID: {}, type: 102", tenantId); } } catch (Exception e) { log.error("从数据库查询支付配置失败,租户ID: {},错误: {}", tenantId, e.getMessage(), e); // 抛出更详细的异常信息 throw PaymentException.systemError("查询支付配置失败,租户ID: " + tenantId + ",错误: " + e.getMessage(), e); } // 数据库也没有配置 if (!"dev".equals(activeProfile)) { throw PaymentException.systemError("微信支付配置未找到,租户ID: " + tenantId + ",请检查数据库配置", null); } log.debug("开发环境模式,将使用测试配置,租户ID: {}", tenantId); // 开发环境返回测试Payment配置 return createDevTestPayment(tenantId); } /** * 获取证书文件路径 */ private String getCertificatePath(Integer tenantId, Payment payment) throws PaymentException { if ("dev".equals(activeProfile)) { return getDevCertificatePath(tenantId); } else { return getProdCertificatePath(payment); } } /** * 获取开发环境证书路径 */ private String getDevCertificatePath(Integer tenantId) throws PaymentException { try { // 根据租户ID构建证书路径 String certPath = "dev/wechat/" + tenantId + "/apiclient_key.pem"; ClassPathResource resource = new ClassPathResource(certPath); if (!resource.exists()) { throw PaymentException.systemError("开发环境微信支付证书文件不存在: " + certPath, null); } String absolutePath = resource.getFile().getAbsolutePath(); log.debug("开发环境证书路径: {}", absolutePath); return absolutePath; } catch (IOException e) { throw PaymentException.systemError("获取开发环境证书路径失败: " + e.getMessage(), e); } } /** * 获取生产环境证书路径 */ private String getProdCertificatePath(Payment payment) throws PaymentException { if (payment == null || payment.getApiclientKey() == null || payment.getApiclientKey().trim().isEmpty()) { throw PaymentException.systemError("生产环境支付配置或证书密钥文件为空", null); } try { // 使用微信支付证书路径 String certificatePath = certificateService.getWechatPayCertPath(payment.getApiclientKey()); if (certificatePath == null) { throw PaymentException.systemError("证书文件路径获取失败,证书文件: " + payment.getApiclientKey(), null); } log.debug("生产环境证书路径: {}", certificatePath); return certificatePath; } catch (Exception e) { throw PaymentException.systemError("获取生产环境证书路径失败: " + e.getMessage(), e); } } /** * 创建微信支付配置对象 */ private Config createWxPayConfig(Payment payment, String certificatePath) throws PaymentException { try { if ("dev".equals(activeProfile) && payment == null) { // 开发环境测试配置 return createDevTestConfig(certificatePath); } else if (payment != null) { // 正常配置 return createNormalConfig(payment, certificatePath); } else { throw PaymentException.systemError("无法创建微信支付配置:配置信息不完整", null); } } catch (Exception e) { if (e instanceof PaymentException) { throw e; } throw PaymentException.systemError("创建微信支付配置对象失败: " + e.getMessage(), e); } } /** * 创建开发环境测试Payment配置 */ private Payment createDevTestPayment(Integer tenantId) { Payment testPayment = new Payment(); testPayment.setTenantId(tenantId); testPayment.setType(102); // Native支付 testPayment.setAppId("wxa67c676fc445590e"); // 开发环境测试AppID testPayment.setMchId("1246610101"); // 开发环境测试商户号 testPayment.setMerchantSerialNumber("48749613B40AA8F1D768583FC352358E13EB5AF0"); testPayment.setApiKey(certificateProperties.getWechatPay().getDev().getApiV3Key()); testPayment.setNotifyUrl("http://frps-10550.s209.websoft.top/api/payment/notify"); testPayment.setName("微信Native支付-开发环境"); testPayment.setStatus(true); // 启用 log.info("创建开发环境测试Payment配置,租户ID: {}, AppID: {}, 商户号: {}", tenantId, testPayment.getAppId(), testPayment.getMchId()); return testPayment; } /** * 创建开发环境测试配置 */ private Config createDevTestConfig(String certificatePath) throws PaymentException { String testMerchantId = "1246610101"; String testMerchantSerialNumber = "48749613B40AA8F1D768583FC352358E13EB5AF0"; String testApiV3Key = certificateProperties.getWechatPay().getDev().getApiV3Key(); if (testApiV3Key == null || testApiV3Key.trim().isEmpty()) { throw PaymentException.systemError("开发环境APIv3密钥未配置", null); } log.info("使用开发环境测试配置"); log.debug("测试商户号: {}", testMerchantId); log.debug("测试序列号: {}", testMerchantSerialNumber); return new RSAAutoCertificateConfig.Builder() .merchantId(testMerchantId) .privateKeyFromPath(certificatePath) .merchantSerialNumber(testMerchantSerialNumber) .apiV3Key(testApiV3Key) .build(); } /** * 创建正常配置 */ private Config createNormalConfig(Payment payment, String certificatePath) throws PaymentException { // 验证配置完整性 validatePaymentConfig(payment); log.info("使用数据库支付配置"); log.debug("商户号: {}", payment.getMchId()); return new RSAAutoCertificateConfig.Builder() .merchantId(payment.getMchId()) .privateKeyFromPath(certificatePath) .merchantSerialNumber(payment.getMerchantSerialNumber()) .apiV3Key(payment.getApiKey()) .build(); } /** * 验证支付配置完整性 */ private void validatePaymentConfig(Payment payment) throws PaymentException { if (payment == null) { throw PaymentException.systemError("支付配置为空", null); } if (payment.getMchId() == null || payment.getMchId().trim().isEmpty()) { throw PaymentException.systemError("商户号(mchId)未配置", null); } if (payment.getMerchantSerialNumber() == null || payment.getMerchantSerialNumber().trim().isEmpty()) { throw PaymentException.systemError("商户证书序列号(merchantSerialNumber)未配置", null); } if (payment.getApiKey() == null || payment.getApiKey().trim().isEmpty()) { throw PaymentException.systemError("APIv3密钥(apiKey)未配置", null); } if (payment.getApiclientKey() == null || payment.getApiclientKey().trim().isEmpty()) { throw PaymentException.systemError("证书文件名(apiclientKey)未配置", null); } log.debug("支付配置验证通过,租户ID: {}, 商户号: {}", payment.getTenantId(), payment.getMchId()); } /** * 清除指定租户的配置缓存 * * @param tenantId 租户ID */ public void clearConfigCache(Integer tenantId) { WxNativeUtil.addConfig(tenantId, null); log.info("清除微信支付配置缓存,租户ID: {}", tenantId); } }