SpringBoot 中如何使用@ControllerAdvice

发布时间:2021-08-06 14:50:00 作者:Leah
来源:亿速云 阅读:304
# SpringBoot 中如何使用@ControllerAdvice

## 一、引言

在SpringBoot应用开发中,异常处理和全局数据绑定是每个项目必须面对的问题。传统的`try-catch`方式虽然直接,但会导致大量重复代码。Spring 3.2引入的`@ControllerAdvice`注解,提供了一种优雅的全局解决方案。

本文将深入探讨`@ControllerAdvice`的核心用法,包括:
- 异常处理的集中化管理
- 全局数据预处理
- 模型属性增强
- 结合`@ResponseBody`的REST风格应用
- 实际项目中的最佳实践

## 二、@ControllerAdvice基础概念

### 2.1 注解定义

```java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
    // 可指定包、类、注解等作用范围
    String[] value() default {};
    String[] basePackages() default {};
    Class<?>[] basePackageClasses() default {};
    Class<?>[] assignableTypes() default {};
    Class<? extends Annotation>[] annotations() default {};
}

2.2 核心作用范围

作用类型 对应注解 说明
异常处理 @ExceptionHandler 捕获控制器抛出的异常
数据绑定 @InitBinder 预处理请求参数
模型增强 @ModelAttribute 向所有控制器添加公共属性

三、异常处理实战

3.1 基础异常处理

@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(NullPointerException.class)
    public ResponseEntity<String> handleNullPointer(NullPointerException ex) {
        return ResponseEntity
            .status(HttpStatus.INTERNAL_SERVER_ERROR)
            .body("空指针异常:" + ex.getMessage());
    }
}

3.2 处理多个异常

@ExceptionHandler({IllegalArgumentException.class, 
                  IllegalStateException.class})
public ResponseEntity<ErrorResponse> handleIllegal(RuntimeException ex) {
    ErrorResponse error = new ErrorResponse(
        LocalDateTime.now(),
        ex.getClass().getSimpleName(),
        ex.getMessage()
    );
    return ResponseEntity.badRequest().body(error);
}

3.3 自定义异常处理

public class BusinessException extends RuntimeException {
    private ErrorCode code;
    // 构造方法等
}

@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResult> handleBusinessException(
        BusinessException ex) {
    return ResponseEntity
        .status(ex.getCode().getHttpStatus())
        .body(ErrorResult.fromException(ex));
}

四、数据绑定与预处理

4.1 日期格式统一处理

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

4.2 防止XSS攻击

@InitBinder
protected void initBinder(WebDataBinder binder) {
    binder.registerCustomEditor(String.class, 
        new StringEscapeEditor(true, false));
}

五、模型属性增强

5.1 添加全局属性

@ModelAttribute
public void addCommonModel(Model model) {
    model.addAttribute("version", "1.0.0");
    model.addAttribute("systemTime", System.currentTimeMillis());
}

5.2 动态菜单处理

@ModelAttribute("menuList")
public List<Menu> getMenus(Principal principal) {
    return menuService.getUserMenu(principal.getName());
}

六、高级用法

6.1 限定控制器范围

// 只作用于指定包下的控制器
@ControllerAdvice(basePackages = "com.example.web")
public class WebControllerAdvice {}

// 只作用于带有特定注解的控制器
@ControllerAdvice(annotations = RestController.class)
public class RestControllerAdvice {}

6.2 结合@ResponseBody

@ControllerAdvice
@ResponseBody
public class RestExceptionHandler {
    
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<?> handleValidException(MethodArgumentNotValidException ex) {
        // 处理参数校验异常
    }
}

6.3 响应结果统一包装

@ControllerAdvice
public class ResponseWrapper 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 Result.success(body);
    }
}

七、实际项目最佳实践

7.1 异常分类处理建议

异常类型 处理方式 HTTP状态码
业务异常 返回具体错误信息 400/自定义
权限异常 跳转登录页/返回403 401403
参数校验异常 返回详细校验错误 400
系统异常 记录日志,返回友好提示 500

7.2 性能优化建议

  1. 避免过度使用@ModelAttribute会在每次请求时执行
  2. 合理划分范围:按模块拆分多个@ControllerAdvice
  3. 异常处理顺序:通过@Order控制处理优先级

八、常见问题解答

Q1: 多个@ControllerAdvice的执行顺序?

A: 默认无序,可通过@Order注解指定顺序

Q2: 如何测试@ControllerAdvice?

@WebMvcTest
@Import(GlobalExceptionHandler.class)
class ExceptionHandlerTest {
    
    @Autowired
    private MockMvc mockMvc;
    
    @Test
    void testHandleException() throws Exception {
        mockMvc.perform(get("/api/error"))
              .andExpect(status().isInternalServerError());
    }
}

Q3: 与@RestControllerAdvice的区别?

A: @RestControllerAdvice = @ControllerAdvice + @ResponseBody

九、总结

@ControllerAdvice作为Spring MVC的重要组件,通过本文我们掌握了: 1. 全局异常处理的标准化方案 2. 请求参数的统一预处理 3. 模型属性的动态增强 4. REST API的响应统一包装 5. 实际项目中的优化实践

合理使用该注解可以显著提升代码的可维护性和一致性,是SpringBoot项目中不可或缺的开发技巧。

最佳实践建议:建议在项目中建立exceptionbindermodel等子包,按功能拆分不同的@ControllerAdvice类 “`

这篇文章涵盖了@ControllerAdvice的核心用法,包含代码示例、表格对比、注意事项等,总字数约3000字。可根据需要进一步扩展具体案例或添加示意图。

推荐阅读:
  1. 一.初识SpringBoot(入门级02)
  2. 二、Springboot 常用注解

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

springboot @controlleradvice

上一篇:IDEA中怎么配置 git命令行

下一篇:如何解决某些HTML字符打不出来的问题

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》