You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从@Controller向@ControllerAdvice传递变量?并在自定义@ControllerAdvice验证处理器中添加额外提示信息

解决方案

一、添加「发票处理失败」的自定义验证提示

要实现这个需求,你可以通过自定义业务异常类结合@ControllerAdvice的全局捕获来完成,步骤清晰且易维护:

  1. 定义自定义异常类
    先创建一个专门针对发票处理的异常类,用来携带错误提示和额外信息:
public class InvoiceProcessingException extends RuntimeException {
    // 可添加额外字段存储需要传递的变量
    private String invoiceNo;
    private String errorDetail;

    // 基础构造方法,传入核心提示信息
    public InvoiceProcessingException(String message) {
        super(message);
    }

    // 重载构造方法,支持携带更多业务变量
    public InvoiceProcessingException(String message, String invoiceNo, String errorDetail) {
        super(message);
        this.invoiceNo = invoiceNo;
        this.errorDetail = errorDetail;
    }

    // getter方法,供全局异常处理器获取变量
    public String getInvoiceNo() {
        return invoiceNo;
    }

    public String getErrorDetail() {
        return errorDetail;
    }
}
  1. 在验证逻辑中抛出异常
    在你的业务验证代码里,当发票不符合处理要求时,直接抛出这个自定义异常,带上「发票处理失败」的提示:
@Service
public class InvoiceService {
    public void processInvoice(InvoiceDTO invoice) {
        // 自定义验证逻辑:比如检查发票号格式、金额是否合法等
        if (isInvalidInvoice(invoice)) {
            // 抛出异常,携带提示信息和关键业务变量
            throw new InvoiceProcessingException("发票处理失败:格式不符合要求", invoice.getInvoiceNo(), "缺少必填字段:发票金额");
        }
        // 正常处理逻辑...
    }

    private boolean isInvalidInvoice(InvoiceDTO invoice) {
        // 你的验证逻辑实现
        return invoice.getInvoiceNo() == null || invoice.getAmount() == null;
    }
}
  1. 在@ControllerAdvice中捕获并返回响应
    在全局异常处理器中,针对InvoiceProcessingException编写专属处理逻辑,将提示信息和变量返回给前端:
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(InvoiceProcessingException.class)
    @ResponseBody
    public ResponseEntity<ErrorResponse> handleInvoiceException(InvoiceProcessingException e) {
        ErrorResponse errorResponse = new ErrorResponse();
        errorResponse.setCode("INVOICE_PROCESS_ERROR");
        errorResponse.setMessage(e.getMessage()); // 这里会包含「发票处理失败」的提示
        // 把异常中的额外变量也返回给前端
        errorResponse.setExtra(Map.of("invoiceNo", e.getInvoiceNo(), "detail", e.getErrorDetail()));
        return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
    }

    // 其他异常处理方法...
}

// 定义统一的错误响应体
class ErrorResponse {
    private String code;
    private String message;
    private Map<String, Object> extra;

    // getter和setter方法
}

二、从@Controller向@ControllerAdvice传递变量

传递变量的核心是让变量和异常或请求上下文绑定,下面两种方案是实际开发中最常用的:

方案1:通过自定义异常类携带变量(推荐)

这是最符合面向对象设计的方式——把需要传递的变量直接封装在自定义异常类中,抛出异常时赋值,在@ControllerAdvice中通过异常对象获取。这种方式逻辑清晰,变量和异常强关联,不会出现上下文污染。

就是上面示例中展示的方式:在InvoiceProcessingException中添加invoiceNo、errorDetail等字段,抛出时传入值,全局异常处理器中通过e.getInvoiceNo()获取。

方案2:通过RequestContextHolder存储请求上下文变量

如果不想修改现有异常类,也可以利用Spring的RequestContextHolder在Controller中存储变量,再在@ControllerAdvice中取出:

  1. 在Controller中存储变量:
@Controller
public class InvoiceController {
    @PostMapping("/invoice/process")
    public ResponseEntity<Void> processInvoice(@RequestBody InvoiceDTO invoice) {
        try {
            // 将变量存入请求上下文
            RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                attributes.setAttribute("currentInvoiceNo", invoice.getInvoiceNo(), RequestAttributes.SCOPE_REQUEST);
            }
            invoiceService.processInvoice(invoice);
            return ResponseEntity.ok().build();
        } catch (Exception e) {
            throw e; // 交给全局异常处理器处理
        }
    }
}
  1. 在@ControllerAdvice中取出变量:
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseEntity<ErrorResponse> handleGenericException(Exception e) {
        ErrorResponse errorResponse = new ErrorResponse();
        errorResponse.setCode("UNKNOWN_ERROR");
        errorResponse.setMessage(e.getMessage());
        
        // 从请求上下文取出变量
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            String invoiceNo = (String) attributes.getAttribute("currentInvoiceNo", RequestAttributes.SCOPE_REQUEST);
            if (invoiceNo != null) {
                errorResponse.setExtra(Map.of("invoiceNo", invoiceNo));
            }
        }
        return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

注意事项

  • 优先选择方案1,它的代码可读性和维护性更好,避免了上下文变量的隐式传递。
  • 如果使用方案2,要注意在异常抛出前完成变量存储,Spring的RequestContextHolder已经做了线程隔离处理,无需担心多线程环境下的安全问题。

内容的提问来源于stack exchange,提问作者Adam Abdullah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 17:28:11