自定义PaymentException类携带orderNo字段,支付业务中抛出该异常并在全局处理器中提取记录订单号。

在支付模块中抛出自定义异常时记录订单号,关键是在异常对象中携带订单号信息,并在全局异常处理器或日志中提取输出。
自定义异常类包含订单号字段
创建继承自 RuntimeException(或 Exception)的异常类,把订单号作为构造参数传入,并提供 getter 方法:
public class PaymentException extends RuntimeException {
private final String orderNo;
public PaymentException(String orderNo, String message) {
super(message);
this.orderNo = orderNo;
}
public PaymentException(String orderNo, String message, Throwable cause) {
super(message, cause);
this.orderNo = orderNo;
}
public String getOrderNo() {
return orderNo;
}
}
在支付业务逻辑中抛出带单号的异常
调用方(如 Service 方法)在检测到异常情况(如余额不足、重复支付、第三方返回失败)时,主动构造并抛出该异常:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
public void processPayment(String orderNo, BigDecimal amount) {
if (amount.compareTo(BigDecimal.ZERO) <= 0) {
throw new PaymentException(orderNo, "支付金额非法");
}
if (!orderRepository.existsById(orderNo)) {
throw new PaymentException(orderNo, "订单不存在");
}
// ... 其他校验与调用
}
全局异常处理器统一记录日志
使用 @ControllerAdvice 捕获异常,在日志中显式打印订单号,便于排查:
立即学习“Java免费学习笔记(深入)”;
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(PaymentException.class)
public ResponseEntity<String> handlePaymentException(PaymentException e) {
String orderNo = e.getOrderNo();
log.error("支付异常,订单号:{},消息:{}", orderNo, e.getMessage(), e);
return ResponseEntity.status(400).body("支付失败:" + e.getMessage());
}
}
补充建议:日志格式与链路追踪对齐
- 确保日志框架(如 Logback)配置了 %X{traceId} 等 MDC 字段,若已集成 SkyWalking 或 Sleuth,可在抛异常前将
orderNo放入 MDC,实现日志自动携带 - 数据库操作失败时,不要只抛通用 SQL 异常,应包装为
PaymentException并传入当前订单号 - 调用第三方支付接口(如微信/支付宝)返回错误码后,也应统一转为该自定义异常,避免订单号丢失

















