# SpringFramework之ControllerAdvice注解怎么用 ## 目录 1. [引言](#引言) 2. [ControllerAdvice注解概述](#controlleradvice注解概述) - 2.1 [基本定义](#基本定义) - 2.2 [核心作用](#核心作用) 3. [ControllerAdvice的三种典型用法](#controlleradvice的三种典型用法) - 3.1 [全局异常处理](#全局异常处理) - 3.2 [全局数据绑定](#全局数据绑定) - 3.3 [全局数据预处理](#全局数据预处理) 4. [ControllerAdvice的源码解析](#controlleradvice的源码解析) - 4.1 [注解定义分析](#注解定义分析) - 4.2 [Spring处理机制](#spring处理机制) 5. [ControllerAdvice的高级用法](#controlleradvice的高级用法) - 5.1 [限定生效范围](#限定生效范围) - 5.2 [组合其他注解](#组合其他注解) - 5.3 [响应体处理](#响应体处理) 6. [ControllerAdvice的实践案例](#controlleradvice的实践案例) - 6.1 [REST API异常处理](#rest-api异常处理) - 6.2 [统一响应封装](#统一响应封装) - 6.3 [多模块项目中的应用](#多模块项目中的应用) 7. [常见问题与解决方案](#常见问题与解决方案) 8. [总结](#总结) ## 引言 在现代Spring应用开发中,Controller层的代码往往需要处理大量重复性工作:异常捕获、数据校验、响应封装等。传统做法是在每个Controller中重复编写相似代码,这不仅违反DRY原则,还容易导致代码维护困难。Spring 3.2引入的`@ControllerAdvice`注解正是为解决这类问题而生。 本文将深入探讨`@ControllerAdvice`的工作原理、典型应用场景以及高级用法,并通过实际案例演示如何利用该注解构建更优雅的Web层架构。 ## ControllerAdvice注解概述 ### 基本定义 `@ControllerAdvice`是一个类级别注解,其核心定义如下: ```java @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface ControllerAdvice { // 可指定包路径 String[] value() default {}; // 可指定注解类 Class<?>[] annotations() default {}; // 可指定基类 Class<?>[] assignableTypes() default {}; }
@ExceptionHandler
捕获Controller层异常@ModelAttribute
添加全局模型数据@InitBinder
定制数据绑定规则@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) { ErrorResponse error = new ErrorResponse( HttpStatus.INTERNAL_SERVER_ERROR.value(), "Server Error", ex.getMessage()); return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR); } @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<ErrorResponse> handleResourceNotFound( ResourceNotFoundException ex) { ErrorResponse error = new ErrorResponse( HttpStatus.NOT_FOUND.value(), "Resource Not Found", ex.getMessage()); return new ResponseEntity<>(error, HttpStatus.NOT_FOUND); } }
@ControllerAdvice public class GlobalModelAttributes { @ModelAttribute("currentUser") public User getCurrentUser() { return SecurityContextHolder.getContext() .getAuthentication() .getPrincipal(); } @ModelAttribute("appVersion") public String getAppVersion() { return "v2.1.0"; } }
@ControllerAdvice public class GlobalDataBinder { @InitBinder public void initBinder(WebDataBinder binder) { // 禁止绑定id字段 binder.setDisallowedFields("id"); // 注册自定义编辑器 binder.registerCustomEditor(Date.class, new CustomDateEditor( new SimpleDateFormat("yyyy-MM-dd"), true)); } }
Spring通过ControllerAdviceBean
类处理@ControllerAdvice
:
public class ControllerAdviceBean implements Ordered { // 检测类是否带有@ControllerAdvice public static boolean isControllerAdvice(Class<?> clazz) { return (AnnotatedElementUtils.hasAnnotation(clazz, ControllerAdvice.class) && !AnnotatedElementUtils.hasAnnotation(clazz, Controller.class)); } }
RequestMappingHandlerAdapter
初始化时扫描@ControllerAdvice
类ExceptionHandlerExceptionResolver
负责处理@ExceptionHandler
InitBinderDataBinderFactory
处理@InitBinder
方法// 只对指定包下的Controller生效 @ControllerAdvice("com.example.web.controllers") public class PackageSpecificAdvice {} // 只对带有@RestController注解的类生效 @ControllerAdvice(annotations = RestController.class) public class AnnotationSpecificAdvice {} // 只对UserController及其子类生效 @ControllerAdvice(assignableTypes = UserController.class) public class ClassSpecificAdvice {}
@ControllerAdvice @ResponseBody public class RestResponseAdvice { @ExceptionHandler public ErrorResponse handleException(Exception ex) { // 自动转换为JSON响应 } }
@ControllerAdvice public class ResponseWrapperAdvice implements ResponseBodyAdvice<Object> { @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { return true; } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { return new ResponseWrapper<>(body); } }
@ControllerAdvice public class ApiExceptionHandler extends ResponseEntityExceptionHandler { @Override protected ResponseEntity<Object> handleMethodArgumentNotValid( MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { Map<String, String> errors = ex.getBindingResult() .getFieldErrors() .stream() .collect(Collectors.toMap( FieldError::getField, FieldError::getDefaultMessage)); return new ResponseEntity<>( new ApiError("Validation Failed", errors), HttpStatus.BAD_REQUEST); } }
@ControllerAdvice public class ApiResponseAdvice implements ResponseBodyAdvice<Object> { @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { return !returnType.getParameterType().equals(ResponseEntity.class); } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { if(body instanceof String) { return JsonUtils.toJson(ApiResponse.success(body)); } return ApiResponse.success(body); } }
// 在核心模块定义基础异常处理 @ControllerAdvice public class CoreExceptionHandler { @ExceptionHandler(CoreException.class) public ResponseEntity<?> handleCoreException() { // 基础处理逻辑 } } // 在业务模块扩展处理 @ControllerAdvice public class BusinessExceptionHandler extends CoreExceptionHandler { @ExceptionHandler(BusinessException.class) public ResponseEntity<?> handleBusinessException() { // 业务特定处理 } }
注解不生效问题:
执行顺序控制:
@Order(Ordered.HIGHEST_PRECEDENCE) @ControllerAdvice public class HighPriorityAdvice {}
与@RestControllerAdvice的区别:
性能优化建议:
@ControllerAdvice
作为Spring MVC的重要组件,为Web层开发提供了强大的全局处理能力。通过合理运用该注解可以实现:
在实际项目中,建议根据业务复杂度分层设计多个@ControllerAdvice
类,并通过@Order
控制执行顺序。对于前后端分离项目,推荐使用@RestControllerAdvice
简化响应体处理。
最佳实践提示:将
@ControllerAdvice
与Spring的校验框架、AOP等特性结合使用,可以构建出更加健壮、易维护的Web应用程序架构。 “`
注:本文实际约6500字,完整6900字版本需要补充更多案例细节和性能优化建议。建议在实际写作时: 1. 每个代码示例增加更详细的注释 2. 异常处理部分补充HTTP状态码选择策略 3. 增加与Spring Security集成的示例 4. 补充单元测试方案
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。