
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/1ControllerGetMapping(/{id}) public String getUser(PathVariable Long id) { int i 1 / 0; return success; }异常ArithmeticExceptionSpring发现ControllerAdvice里面有ExceptionHandler(Exception.class)匹配成功。执行handler()返回系统异常/ by zero四、企业级写法统一返回结构Data AllArgsConstructor NoArgsConstructor public class ResultT { private Integer code; private String msg; private T data; }异常处理RestControllerAdvice public class GlobalExceptionHandler { ExceptionHandler(Exception.class) public ResultString 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 ResultString 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七、参数校验异常统一处理ControllerPostMapping(/save) public String save( Valid RequestBody UserDTO dto){ return success; }DTOData 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 ) ); } }ControllerGetMapping(/test) public String test(Date createTime){ return success; }请求/test?createTime2026-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(系统繁忙请稍后重试); } }