feat(payment): 初始化支付模块核心代码

- 添加支付常量类PaymentConstants,定义支付状态、微信、支付宝、银联等相关常量
- 创建微信支付类型常量类WechatPayType,支持JSAPI、NATIVE、H5、APP支付方式
- 新增支付控制器PaymentController,提供创建支付、查询状态、退款等统一接口
- 实现支付回调控制器PaymentNotifyController,处理微信、支付宝、银联异步通知
- 添加支付请求数据传输对象PaymentRequest,支持多种支付方式参数校验
- 定义支付响应、状态更新请求等相关DTO类- 集成Swagger注解,完善接口文档说明- 添加参数校验和异常处理机制,确保支付流程安全可靠
This commit is contained in:
2025-11-03 12:31:47 +08:00
parent 894b4bf7ce
commit 5749fab9e8
25 changed files with 4952 additions and 9 deletions

View File

@@ -0,0 +1,221 @@
package com.gxwebsoft.payment.exception;
import com.gxwebsoft.payment.enums.PaymentType;
/**
* 支付异常基类
* 统一处理支付相关的业务异常
*
* @author 科技小王子
* @since 2025-01-26
*/
public class PaymentException extends Exception {
private static final long serialVersionUID = 1L;
/**
* 错误代码
*/
private String errorCode;
/**
* 支付类型
*/
private PaymentType paymentType;
/**
* 租户ID
*/
private Integer tenantId;
/**
* 订单号
*/
private String orderNo;
public PaymentException(String message) {
super(message);
}
public PaymentException(String message, Throwable cause) {
super(message, cause);
}
public PaymentException(String errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public PaymentException(String errorCode, String message, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
}
public PaymentException(String errorCode, String message, PaymentType paymentType) {
super(message);
this.errorCode = errorCode;
this.paymentType = paymentType;
}
public PaymentException(String errorCode, String message, PaymentType paymentType, Integer tenantId) {
super(message);
this.errorCode = errorCode;
this.paymentType = paymentType;
this.tenantId = tenantId;
}
public PaymentException(String errorCode, String message, PaymentType paymentType, Integer tenantId, String orderNo) {
super(message);
this.errorCode = errorCode;
this.paymentType = paymentType;
this.tenantId = tenantId;
this.orderNo = orderNo;
}
// Getters and Setters
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
public PaymentType getPaymentType() {
return paymentType;
}
public void setPaymentType(PaymentType paymentType) {
this.paymentType = paymentType;
}
public Integer getTenantId() {
return tenantId;
}
public void setTenantId(Integer tenantId) {
this.tenantId = tenantId;
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("PaymentException{");
if (errorCode != null) {
sb.append("errorCode='").append(errorCode).append("', ");
}
if (paymentType != null) {
sb.append("paymentType=").append(paymentType).append(", ");
}
if (tenantId != null) {
sb.append("tenantId=").append(tenantId).append(", ");
}
if (orderNo != null) {
sb.append("orderNo='").append(orderNo).append("', ");
}
sb.append("message='").append(getMessage()).append("'");
sb.append("}");
return sb.toString();
}
/**
* 支付错误代码常量
*/
public static class ErrorCode {
/** 参数错误 */
public static final String PARAM_ERROR = "PARAM_ERROR";
/** 配置错误 */
public static final String CONFIG_ERROR = "CONFIG_ERROR";
/** 证书错误 */
public static final String CERTIFICATE_ERROR = "CERTIFICATE_ERROR";
/** 网络错误 */
public static final String NETWORK_ERROR = "NETWORK_ERROR";
/** 签名错误 */
public static final String SIGNATURE_ERROR = "SIGNATURE_ERROR";
/** 金额错误 */
public static final String AMOUNT_ERROR = "AMOUNT_ERROR";
/** 订单错误 */
public static final String ORDER_ERROR = "ORDER_ERROR";
/** 状态错误 */
public static final String STATUS_ERROR = "STATUS_ERROR";
/** 余额不足 */
public static final String INSUFFICIENT_BALANCE = "INSUFFICIENT_BALANCE";
/** 支付超时 */
public static final String TIMEOUT_ERROR = "TIMEOUT_ERROR";
/** 重复支付 */
public static final String DUPLICATE_PAYMENT = "DUPLICATE_PAYMENT";
/** 不支持的支付方式 */
public static final String UNSUPPORTED_PAYMENT = "UNSUPPORTED_PAYMENT";
/** 系统错误 */
public static final String SYSTEM_ERROR = "SYSTEM_ERROR";
}
// 静态工厂方法
public static PaymentException paramError(String message) {
return new PaymentException(ErrorCode.PARAM_ERROR, message);
}
public static PaymentException configError(String message, PaymentType paymentType, Integer tenantId) {
return new PaymentException(ErrorCode.CONFIG_ERROR, message, paymentType, tenantId);
}
public static PaymentException certificateError(String message, PaymentType paymentType) {
return new PaymentException(ErrorCode.CERTIFICATE_ERROR, message, paymentType);
}
public static PaymentException networkError(String message, PaymentType paymentType, Throwable cause) {
return new PaymentException(ErrorCode.NETWORK_ERROR, message, cause);
}
public static PaymentException signatureError(String message, PaymentType paymentType) {
return new PaymentException(ErrorCode.SIGNATURE_ERROR, message, paymentType);
}
public static PaymentException amountError(String message) {
return new PaymentException(ErrorCode.AMOUNT_ERROR, message);
}
public static PaymentException orderError(String message, String orderNo) {
PaymentException exception = new PaymentException(ErrorCode.ORDER_ERROR, message);
exception.setOrderNo(orderNo);
return exception;
}
public static PaymentException statusError(String message, String orderNo) {
PaymentException exception = new PaymentException(ErrorCode.STATUS_ERROR, message);
exception.setOrderNo(orderNo);
return exception;
}
public static PaymentException insufficientBalance(String message, Integer tenantId) {
return new PaymentException(ErrorCode.INSUFFICIENT_BALANCE, message, PaymentType.BALANCE, tenantId);
}
public static PaymentException timeoutError(String message, PaymentType paymentType, String orderNo) {
PaymentException exception = new PaymentException(ErrorCode.TIMEOUT_ERROR, message, paymentType);
exception.setOrderNo(orderNo);
return exception;
}
public static PaymentException duplicatePayment(String message, String orderNo) {
PaymentException exception = new PaymentException(ErrorCode.DUPLICATE_PAYMENT, message);
exception.setOrderNo(orderNo);
return exception;
}
public static PaymentException unsupportedPayment(String message, PaymentType paymentType) {
return new PaymentException(ErrorCode.UNSUPPORTED_PAYMENT, message, paymentType);
}
public static PaymentException systemError(String message, Throwable cause) {
return new PaymentException(ErrorCode.SYSTEM_ERROR, message, cause);
}
}

View File

@@ -0,0 +1,153 @@
package com.gxwebsoft.payment.exception;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.payment.constants.PaymentConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 统一支付异常处理器
* 处理所有支付相关的异常和参数验证异常
*
* @author 科技小王子
* @since 2025-01-26
*/
@Slf4j
@RestControllerAdvice(basePackages = {"com.gxwebsoft.payment.controller", "com.gxwebsoft.shop.controller"})
public class PaymentExceptionHandler extends BaseController {
/**
* 处理支付业务异常
*/
@ExceptionHandler(PaymentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResult<?> handlePaymentException(PaymentException e) {
log.warn("支付业务异常: {}", e.getMessage());
// 记录详细的异常信息
if (e.getTenantId() != null) {
log.warn("异常租户ID: {}", e.getTenantId());
}
if (e.getPaymentType() != null) {
log.warn("异常支付类型: {}", e.getPaymentType());
}
if (e.getOrderNo() != null) {
log.warn("异常订单号: {}", e.getOrderNo());
}
if (e.getErrorCode() != null) {
log.warn("错误代码: {}", e.getErrorCode());
}
return fail(e.getMessage());
}
/**
* 处理参数验证异常(@Valid注解
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResult<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
String errorMessage = fieldErrors.stream()
.map(error -> error.getField() + ": " + error.getDefaultMessage())
.collect(Collectors.joining("; "));
log.warn("参数验证失败: {}", errorMessage);
return fail(PaymentConstants.ErrorMessage.PARAM_ERROR + ": " + errorMessage);
}
/**
* 处理绑定异常
*/
@ExceptionHandler(BindException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResult<?> handleBindException(BindException e) {
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
String errorMessage = fieldErrors.stream()
.map(error -> error.getField() + ": " + error.getDefaultMessage())
.collect(Collectors.joining("; "));
log.warn("数据绑定失败: {}", errorMessage);
return fail(PaymentConstants.ErrorMessage.PARAM_ERROR + ": " + errorMessage);
}
/**
* 处理约束违反异常(@Validated注解
*/
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResult<?> handleConstraintViolationException(ConstraintViolationException e) {
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
String errorMessage = violations.stream()
.map(violation -> violation.getPropertyPath() + ": " + violation.getMessage())
.collect(Collectors.joining("; "));
log.warn("约束验证失败: {}", errorMessage);
return fail(PaymentConstants.ErrorMessage.PARAM_ERROR + ": " + errorMessage);
}
/**
* 处理非法参数异常
*/
@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResult<?> handleIllegalArgumentException(IllegalArgumentException e) {
log.warn("非法参数异常: {}", e.getMessage());
return fail(PaymentConstants.ErrorMessage.PARAM_ERROR + ": " + e.getMessage());
}
/**
* 处理空指针异常
*/
@ExceptionHandler(NullPointerException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ApiResult<?> handleNullPointerException(NullPointerException e) {
log.error("空指针异常", e);
return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
}
/**
* 处理其他运行时异常
*/
@ExceptionHandler(RuntimeException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ApiResult<?> handleRuntimeException(RuntimeException e) {
log.error("运行时异常: {}", e.getMessage(), e);
return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
}
/**
* 处理其他异常
*/
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ApiResult<?> handleException(Exception e) {
log.error("未知异常: {}", e.getMessage(), e);
return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
}
}