@ControllerAdvice 是 Spring MVC 中的一个全局增强组件。

它的作用可以理解为:

给所有 @Controller 或

@RestController 统一增加公共能力。

最常见的用途:

1. 全局异常处理
2. 全局数据绑定
3. 全局参数预处理
4. 全局返回值封装

面试中经常问:

Spring Boot 如何实现统一异常处理?

答案基本就是:

@ControllerAdvice
+ @ExceptionHandler

一、没有@ControllerAdvice的问题

假设有一个查询用户接口

@RestController
@RequestMapping("/user")
public class UserController {
    @GetMapping("/{id}")
    public String getUser(@PathVariable Long id) {
        int i = 1 / 0;
        return "success";
    }
}

访问:

GET /user/1

结果:

{
  "timestamp":"2025-06-03",
  "status":500,
  "error":"Internal Server Error"
}

返回一大堆 Spring 默认异常信息。

如果项目有:

100个Controller
1000个接口

每个接口都写:

try{
    ...
}catch(Exception e){
    ...
}

会非常恶心。

二、@ControllerAdvice出现

创建:

@ControllerAdvice
public class GlobalExceptionHandler {
}

它会被 Spring 扫描。

然后监听异常:

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public String handler(Exception e){
        return "系统异常:" + e.getMessage();
    }
}

三、执行流程

请求:

GET /user/1

Controller:

@GetMapping("/{id}")
public String getUser(@PathVariable Long id) {
    int i = 1 / 0;
    return "success";
}

异常:

ArithmeticException

Spring发现:

@ControllerAdvice

里面有:

@ExceptionHandler(Exception.class)

匹配成功。

执行:

handler()

返回:

系统异常:/ by zero

四、企业级写法

统一返回结构:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result<T> {
    private Integer code;
    private String msg;
    private T data;
}

异常处理:

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public Result<String> handler(Exception e){
        return new Result<>(
                500,
                e.getMessage(),
                null
        );
    }
}

注意:

@RestControllerAdvice
=
@ControllerAdvice
+
@ResponseBody

实际项目几乎都用:

@RestControllerAdvice

五、自定义异常

例如用户不存在。

定义异常:

public class UserNotFoundException extends RuntimeException {
    public UserNotFoundException(String msg){
        super(msg);
    }
}

业务代码:

@GetMapping("/{id}")
public String getUser(@PathVariable Long id){
    if(id == 0){
        throw new UserNotFoundException("用户不存在");
    }
    return "张三";
}

处理指定异常:

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(UserNotFoundException.class)
    public Result<String> userException(
            UserNotFoundException e){
        return new Result<>(
                404,
                e.getMessage(),
                null
        );
    }
}

结果:

{
    "code":404,
    "msg":"用户不存在",
    "data":null
}

六、多个异常处理方法

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(UserNotFoundException.class)
    public Result<?> userException(
            UserNotFoundException e){
        return Result.fail(e.getMessage());
    }
    @ExceptionHandler(SQLException.class)
    public Result<?> sqlException(
            SQLException e){
        return Result.fail("数据库异常");
    }
    @ExceptionHandler(Exception.class)
    public Result<?> exception(
            Exception e){
        return Result.fail("系统异常");
    }
}

匹配规则:

先找具体异常
再找父异常
最后Exception

例如:

NullPointerException

会走:

Exception.class

七、参数校验异常统一处理

Controller:

@PostMapping("/save")
public String save(
        @Valid @RequestBody UserDTO dto){
    return "success";
}

DTO:

@Data
public class UserDTO {
    @NotBlank
    private String name;
}

用户传:

{
}

抛出:

MethodArgumentNotValidException

统一处理:

@ExceptionHandler(
        MethodArgumentNotValidException.class)
public Result<?> validException(
        MethodArgumentNotValidException e){
    String msg =
            e.getBindingResult()
             .getFieldError()
             .getDefaultMessage();
    return Result.fail(msg);
}

返回:

{
    "code":400,
    "msg":"name不能为空"
}

八、@InitBinder

除了异常处理,

@ControllerAdvice 还能做全局参数绑定。

例如日期格式转换:

@ControllerAdvice
public class GlobalBinding {
    @InitBinder
    public void initBinder(WebDataBinder binder){
        SimpleDateFormat sdf =
                new SimpleDateFormat(
                        "yyyy-MM-dd");
        binder.registerCustomEditor(
                Date.class,
                new CustomDateEditor(
                        sdf,
                        true
                )
        );
    }
}

Controller:

@GetMapping("/test")
public String test(Date createTime){
    return "success";
}

请求:

/test?createTime=2026-06-04

自动转换:

Date

九、@ModelAttribute

全局添加公共数据。

@ControllerAdvice
public class GlobalModel {
    @ModelAttribute
    public void addAttr(Model model){
        model.addAttribute(
                "version",
                "1.0"
        );
    }
}

所有 Controller 都能拿到:

model.getAttribute("version");

十、标准答案

问:

@ControllerAdvice有什么作用?

回答:

@ControllerAdvice 是 Spring MVC 提供的全局增强组件,可以对所有 Controller 进行统一处理。最常用于全局异常处理(配合 @ExceptionHandler)、全局参数绑定(@InitBinder)以及全局模型数据设置(@ModelAttribute)。在 Spring Boot 项目中通常使用 @RestControllerAdvice 实现统一异常返回,避免在每个接口中编写重复的 try-catch 代码。

企业项目里最常见的代码组合是:

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(BusinessException.class)
    public Result<?> businessException(
            BusinessException e){
        return Result.fail(e.getMessage());
    }
    @ExceptionHandler(Exception.class)
    public Result<?> exception(
            Exception e){
        return Result.fail("系统繁忙,请稍后重试");
    }
}
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐