@ControllerAdvice 是 Spring 统一处理 Controller 层异常的机制,需配合 @ExceptionHandler 使用,仅拦截已进入 MVC 流程且在 Controller 方法执行中抛出的异常;推荐使用 @RestControllerAdvice 以简化 JSON 响应。

@ControllerAdvice 是 Spring 提供的专门用于统一处理 Controller 层异常的核心机制,它本身不捕获异常,而是声明一个“异常处理注册中心”,配合 @ExceptionHandler 方法,对所有被 DispatcherServlet 路由到 Controller 并执行过程中抛出的异常进行拦截和响应。
只管 Controller 层,范围很明确
它只处理以下情况:
- 请求已进入 Spring MVC 流程,成功匹配到某个 @Controller 或 @RestController 方法
- 该方法在执行中抛出了未被捕获的异常(比如业务逻辑中 throw new BusinessException())
- 参数校验失败触发的异常,如 @Valid + @RequestBody 抛出的 MethodArgumentNotValidException
它不管这些:
- Filter、Interceptor 中抛出的异常
- 请求根本没进 Controller(如 404 找不到接口、静态资源访问错误)
- 容器启动失败、JSON 解析早期失败等非 Controller 执行阶段的问题
推荐用 @RestControllerAdvice 替代 @ControllerAdvice
前后端分离项目基本都返回 JSON,直接用 @RestControllerAdvice 更简洁,它等价于 @ControllerAdvice + @ResponseBody,不用每个方法再加 @ResponseBody。
立即学习“Java免费学习笔记(深入)”;
基础写法示例:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NullPointerException.class)
public Result handleNpe(NullPointerException e) {
return Result.error("参数不能为空");
}
@ExceptionHandler(BusinessException.class)
public Result handleBiz(BusinessException e) {
return Result.error(e.getCode(), e.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result handleValid(MethodArgumentNotValidException e) {
String msg = e.getBindingResult()
.getFieldErrors()
.stream()
.map(fe -> fe.getField() + ": " + fe.getDefaultMessage())
.collect(Collectors.joining("; "));
return Result.error(400, msg);
}
@ExceptionHandler(Exception.class)
public Result handleOther(Exception e) {
// 生产环境建议记录日志,且不暴露堆栈
log.error("未预期异常", e);
return Result.error(500, "服务暂不可用");
}
}
精准控制生效范围,避免误伤
可以通过属性限定这个异常处理器只作用于你关心的部分:
- 按包限定:@RestControllerAdvice(basePackages = "com.example.api")
- 按注解限定:@RestControllerAdvice(annotations = RestController.class)
- 按类限定:@RestControllerAdvice(assignableTypes = {OrderController.class})
多个条件可同时使用,Spring 会取交集。异常匹配遵循子类优先原则——比如同时定义了 handle(Exception) 和 handle(BusinessException),当 BusinessException 抛出时,优先调用后者。
配合 JSR-303 校验异常一起处理
只要 Controller 方法参数用了 @Valid 或 @Validated,校验失败就会自动抛出对应异常:
- @RequestBody + @Valid → 抛 MethodArgumentNotValidException
- @RequestParam/@PathVariable + 约束注解 + @Validated → 抛 ConstraintViolationException
把这些异常类型也写进 @ExceptionHandler,就能统一格式返回错误字段和提示,前端无需解析不同结构的报错信息。


















