Browse Source

feat(payment): 增加支付配置检查和最近支付查询功能- 新增支付配置检查接口,用于检查指定租户的支付配置是否完整

- 添加查询用户最近支付订单接口,当orderNo缺失时可查询用户最近创建的支付订单
- 优化订单号生成逻辑,使用雪花算法保证全局唯一
- 完善支付配置验证,确保商户号、序列号、API密钥等关键信息已配置
- 调整日志输出,增加关键信息的空值检查和异常处理
pan
科技小王子 1 month ago
parent
commit
21bdd6c87e
  1. 55
      src/main/java/com/gxwebsoft/payment/controller/PaymentController.java
  2. 8
      src/main/java/com/gxwebsoft/payment/service/PaymentService.java
  3. 57
      src/main/java/com/gxwebsoft/payment/service/WxPayConfigService.java
  4. 49
      src/main/java/com/gxwebsoft/payment/service/impl/PaymentServiceImpl.java
  5. 13
      src/main/java/com/gxwebsoft/payment/strategy/WechatNativeStrategy.java
  6. 2
      src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java

55
src/main/java/com/gxwebsoft/payment/controller/PaymentController.java

@ -112,6 +112,17 @@ public class PaymentController extends BaseController {
log.info("查询支付状态: orderNo={}, paymentType={}, tenantId={}", orderNo, paymentType, tenantId);
// 参数验证
if (orderNo == null || orderNo.trim().isEmpty()) {
return fail("订单号不能为空");
}
if (paymentType == null) {
return fail("支付类型不能为空");
}
if (tenantId == null || tenantId <= 0) {
return fail("租户ID不能为空且必须为正数");
}
try {
PaymentResponse response = paymentService.queryPayment(orderNo, paymentType, tenantId);
return this.<PaymentResponse>success("支付状态查询成功", response);
@ -302,4 +313,48 @@ public class PaymentController extends BaseController {
return fail("更新支付状态失败: " + e.getMessage());
}
}
@Operation(summary = "检查支付配置", description = "检查指定租户的支付配置是否完整")
@GetMapping("/config/check")
public ApiResult<?> checkPaymentConfig(
@Parameter(description = "租户ID", required = true)
@RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) {
log.info("检查支付配置,租户ID: {}", tenantId);
try {
Map<String, Object> configStatus = paymentService.checkPaymentConfig(tenantId);
return this.<Map<String, Object>>success("配置检查完成", configStatus);
} catch (Exception e) {
log.error("检查支付配置失败: {}", e.getMessage(), e);
return fail("检查支付配置失败: " + e.getMessage());
}
}
@Operation(summary = "查询用户最近的支付订单", description = "当orderNo缺失时,查询用户最近创建的支付订单")
@GetMapping("/query-recent")
public ApiResult<?> queryRecentPayment(
@Parameter(description = "支付类型", required = true)
@RequestParam @NotNull(message = "支付类型不能为空") PaymentType paymentType,
@Parameter(description = "租户ID", required = true)
@RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) {
log.info("查询用户最近支付订单: paymentType={}, tenantId={}", paymentType, tenantId);
final User loginUser = getLoginUser();
if(loginUser == null){
return fail("请先登录");
}
try {
// 这里需要实现查询用户最近订单的逻辑
// 可以通过用户ID和租户ID查询最近创建的订单
return fail("此功能需要实现查询用户最近订单的业务逻辑");
} catch (Exception e) {
log.error("查询用户最近支付订单失败: {}", e.getMessage(), e);
return fail("查询失败: " + e.getMessage());
}
}
}

8
src/main/java/com/gxwebsoft/payment/service/PaymentService.java

@ -171,4 +171,12 @@ public interface PaymentService {
* @return 所有策略信息列表
*/
List<Map<String, Object>> getAllPaymentStrategyInfo();
/**
* 检查支付配置
*
* @param tenantId 租户ID
* @return 配置检查结果
*/
Map<String, Object> checkPaymentConfig(Integer tenantId);
}

57
src/main/java/com/gxwebsoft/payment/service/WxPayConfigService.java

@ -126,19 +126,26 @@ public class WxPayConfigService {
// 缓存中没有,尝试从数据库查询
try {
final PaymentParam paymentParam = new PaymentParam();
paymentParam.setType(102);
paymentParam.setTenantId(tenantId);
payment = paymentService.getByType(paymentParam);
System.out.println("payment1 = " + payment);
if (payment != null) {
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);
// 将查询到的配置缓存起来,缓存1
redisUtil.set(cacheKey, payment, 1L, TimeUnit.DAYS);
return payment;
} else {
log.warn("数据库中未找到支付配置,租户ID: {}, type: 102", tenantId);
}
} catch (Exception e) {
log.warn("从数据库查询支付配置失败,租户ID: {},错误: {}", tenantId, e.getMessage());
log.error("从数据库查询支付配置失败,租户ID: {},错误: {}", tenantId, e.getMessage(), e);
// 抛出更详细的异常信息
throw PaymentException.systemError("查询支付配置失败,租户ID: " + tenantId + ",错误: " + e.getMessage(), e);
}
// 数据库也没有配置
@ -278,9 +285,8 @@ public class WxPayConfigService {
* 创建正常配置
*/
private Config createNormalConfig(Payment payment, String certificatePath) throws PaymentException {
if (payment.getMchId() == null || payment.getMerchantSerialNumber() == null || payment.getApiKey() == null) {
throw PaymentException.systemError("支付配置信息不完整:商户号、序列号或APIv3密钥为空", null);
}
// 验证配置完整性
validatePaymentConfig(payment);
log.info("使用数据库支付配置");
log.debug("商户号: {}", payment.getMchId());
@ -293,6 +299,33 @@ public class WxPayConfigService {
.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());
}
/**
* 清除指定租户的配置缓存
*

49
src/main/java/com/gxwebsoft/payment/service/impl/PaymentServiceImpl.java

@ -1,5 +1,7 @@
package com.gxwebsoft.payment.service.impl;
import cn.hutool.core.util.IdUtil;
import com.gxwebsoft.common.core.utils.CommonUtil;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.payment.constants.PaymentConstants;
import com.gxwebsoft.payment.dto.PaymentRequest;
@ -8,6 +10,7 @@ import com.gxwebsoft.payment.dto.PaymentWithOrderRequest;
import com.gxwebsoft.payment.enums.PaymentType;
import com.gxwebsoft.payment.exception.PaymentException;
import com.gxwebsoft.payment.service.PaymentService;
import com.gxwebsoft.payment.service.WxPayConfigService;
import com.gxwebsoft.payment.strategy.PaymentStrategy;
import com.gxwebsoft.shop.dto.OrderCreateRequest;
import com.gxwebsoft.shop.service.OrderBusinessService;
@ -50,6 +53,12 @@ public class PaymentServiceImpl implements PaymentService {
@Resource
private OrderBusinessService orderBusinessService;
/**
* 微信支付配置服务
*/
@Resource
private WxPayConfigService wxPayConfigService;
/**
* 初始化策略映射
*/
@ -416,6 +425,34 @@ public class PaymentServiceImpl implements PaymentService {
.collect(Collectors.toList());
}
@Override
public Map<String, Object> checkPaymentConfig(Integer tenantId) {
Map<String, Object> result = new HashMap<>();
result.put("tenantId", tenantId);
try {
// 检查微信支付配置
wxPayConfigService.getPaymentConfigForStrategy(tenantId);
result.put("wechatConfigExists", true);
result.put("wechatConfigError", null);
} catch (Exception e) {
result.put("wechatConfigExists", false);
result.put("wechatConfigError", e.getMessage());
}
try {
// 检查微信支付Config构建
wxPayConfigService.getWxPayConfig(tenantId);
result.put("wechatConfigValid", true);
result.put("wechatConfigValidError", null);
} catch (Exception e) {
result.put("wechatConfigValid", false);
result.put("wechatConfigValidError", e.getMessage());
}
return result;
}
/**
* 获取支付策略
*/
@ -554,6 +591,11 @@ public class PaymentServiceImpl implements PaymentService {
private OrderCreateRequest convertToOrderCreateRequest(PaymentWithOrderRequest request, User loginUser) {
OrderCreateRequest orderRequest = new OrderCreateRequest();
// 生成订单号(使用雪花算法保证全局唯一)
String orderNo = Long.toString(IdUtil.getSnowflakeNextId());
orderRequest.setOrderNo(orderNo);
log.info("为订单创建请求生成订单号(雪花算法): {}", orderNo);
// 设置基本信息
orderRequest.setType(request.getOrderInfo().getType());
orderRequest.setTitle(request.getSubject());
@ -614,8 +656,13 @@ public class PaymentServiceImpl implements PaymentService {
// 设置额外信息
response.setSuccess(true);
// 确保orderNo被正确设置
response.setOrderNo(orderNo);
// 调试日志
log.info("构建支付响应成功, 订单号: {}, 二维码URL: {}, 响应中的orderNo: {}",
orderNo, wxOrderInfo.get("codeUrl"), response.getOrderNo());
log.debug("构建支付响应成功, 订单号: {}, 二维码URL: {}", orderNo, wxOrderInfo.get("codeUrl"));
return response;
}
}

13
src/main/java/com/gxwebsoft/payment/strategy/WechatNativeStrategy.java

@ -1,5 +1,6 @@
package com.gxwebsoft.payment.strategy;
import cn.hutool.core.util.IdUtil;
import com.gxwebsoft.common.core.utils.CommonUtil;
import com.gxwebsoft.common.system.entity.Payment;
import com.gxwebsoft.payment.constants.PaymentConstants;
@ -99,6 +100,7 @@ public class WechatNativeStrategy implements PaymentStrategy {
// 生成订单号
String orderNo = generateOrderNo(request);
log.info("生成的订单号: {}", orderNo);
// 获取Native支付的Payment配置(包含appId等信息)
Payment paymentConfig = wxPayConfigService.getPaymentConfigForStrategy(request.getTenantId());
@ -117,6 +119,13 @@ public class WechatNativeStrategy implements PaymentStrategy {
orderNo, prepayResponse.getCodeUrl(), request.getAmount(), request.getTenantId());
response.setUserId(request.getUserId());
// 确保orderNo被正确设置
response.setOrderNo(orderNo);
// 调试日志:检查响应对象的orderNo
log.info("构建的响应对象 - orderNo: {}, codeUrl: {}, success: {}",
response.getOrderNo(), response.getCodeUrl(), response.getSuccess());
log.info("{}, 支付类型: {}, 租户ID: {}, 订单号: {}, 金额: {}",
PaymentConstants.LogMessage.PAYMENT_SUCCESS, getSupportedPaymentType(),
request.getTenantId(), orderNo, request.getFormattedAmount());
@ -224,13 +233,13 @@ public class WechatNativeStrategy implements PaymentStrategy {
}
/**
* 生成订单号
* 生成订单号使用雪花算法保证全局唯一
*/
private String generateOrderNo(PaymentRequest request) {
if (StringUtils.hasText(request.getOrderNo())) {
return request.getOrderNo();
}
return CommonUtil.createOrderNo();
return Long.toString(IdUtil.getSnowflakeNextId());
}

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

@ -995,7 +995,7 @@ public class ShopOrderServiceImpl extends ServiceImpl<ShopOrderMapper, ShopOrder
System.out.println("🔧 使用RSA自动证书配置");
config = new RSAAutoCertificateConfig.Builder()
.merchantId(payment.getMchId())
.privateKey(privateKey)
.privateKeyFromPath(privateKey)
.merchantSerialNumber(payment.getMerchantSerialNumber())
.apiV3Key(payment.getApiKey())
.build();

Loading…
Cancel
Save