严格来说, 本文并不算是 Spring Boot 中的知识点, 但是很多学过 SpringMVC 的小伙伴, 对于 @ControllerAdvice 却并不熟悉, Spring Boot 和 SpringMVC 一脉相承,@ControllerAdvice 在 Spring Boot 中也有广泛的使用场景, 因此本文我们就来聊一聊这个问题.
@ControllerAdvice , 很多初学者可能都没有听说过这个注解, 实际上, 这是一个非常有用的注解, 顾名思义, 这是一个增强的 Controller. 使用这个 Controller , 可以实现三个方面的功能:
全局异常处理
全局数据绑定
全局数据预处理
灵活使用这三个功能, 可以帮助我们简化很多工作, 需要注意的是, 这是 SpringMVC 提供的功能, 在 Spring Boot 中可以直接使用, 下面分别来看.
全局异常处理
使用 @ControllerAdvice 实现全局异常处理, 只需要定义类, 添加该注解即可定义方式如下:
- @ControllerAdvice
- public class MyGlobalExceptionHandler {
- @ExceptionHandler(Exception.class)
- public ModelAndView customException(Exception e) {
- ModelAndView mv = new ModelAndView();
- mv.addObject("message", e.getMessage());
- mv.setViewName("myerror");
- return mv;
- }
- }
在该类中, 可以定义多个方法, 不同的方法处理不同的异常, 例如专门处理空指针的方法, 专门处理数组越界的方法..., 也可以直接向上面代码一样, 在一个方法中处理所有的异常信息.
@ExceptionHandler 注解用来指明异常的处理类型, 即如果这里指定为 NullpointerException, 则数组越界异常就不会进到这个方法中来.
全局数据绑定
全局数据绑定功能可以用来做一些初始化的数据操作, 我们可以将一些公共的数据定义在添加了 @ControllerAdvice 注解的类中, 这样, 在每一个 Controller 的接口中, 就都能够访问导致这些数据.
使用步骤, 首先定义全局数据, 如下:
- @ControllerAdvice
- public class MyGlobalExceptionHandler {
- @ModelAttribute(name = "md")
- public Map<String,Object> mydata() {
- HashMap<String, Object> map = new HashMap<>();
- map.put("age", 99);
- map.put("gender", "男");
- return map;
- }
- }
使用 @ModelAttribute 注解标记该方法的返回数据是一个全局数据, 默认情况下, 这个全局数据的 key 就是返回的变量名, value 就是方法返回值, 当然开发者可以通过 @ModelAttribute 注解的 name 属性去重新指定 key.
定义完成后, 在任何一个 Controller 的接口中, 都可以获取到这里定义的数据:
- @RestController
- public class HelloController {
- @GetMapping("/hello")
- public String hello(Model model) {
- Map<String, Object> map = model.asMap();
- System.out.println(map);
- int i = 1 / 0;
- return "hello controller advice";
- }
- }
全局数据预处理
考虑我有两个实体类, Book 和 Author, 分别定义如下:
- public class Book {
- private String name;
- private Long price;
- //getter/setter
- }
- public class Author {
- private String name;
- private Integer age;
- //getter/setter
- }
此时, 如果我定义一个数据添加接口, 如下:
- @PostMapping("/book")
- public void addBook(Book book, Author author) {
- System.out.println(book);
- System.out.println(author);
- }
这个时候, 添加操作就会有问题, 因为两个实体类都有一个 name 属性, 从前端传递时 , 无法区分. 此时, 通过 @ControllerAdvice 的全局数据预处理可以解决这个问题
解决步骤如下:
1. 给接口中的变量取别名
- @PostMapping("/book")
- public void addBook(@ModelAttribute("b") Book book, @ModelAttribute("a") Author author) {
- System.out.println(book);
- System.out.println(author);
- }
2. 进行请求数据预处理
在 @ControllerAdvice 标记的类中添加如下代码:
- @InitBinder("b")
- public void b(webDataBinder binder) {
- binder.setFieldDefaultPrefix("b.");
- }
- @InitBinder("a")
- public void a(WebDataBinder binder) {
- binder.setFieldDefaultPrefix("a.");
- }
@InitBinder("b") 注解表示该方法用来处理和 Book 和相关的参数, 在方法中, 给参数添加一个 b 前缀, 即请求参数要有 b 前缀.
3. 发送请求
请求发送时, 通过给不同对象的参数添加不同的前缀, 可以实现参数的区分.
总结
这就是松哥给大伙介绍的 @ControllerAdvice 的几个简单用法, 这些点既可以在传统的 SSM 项目中使用, 也可以在 Spring Boot + Spring Cloud 微服务中使用, 欢迎大家有问题一起讨论.
关注公众号 [江南一点雨] , 专注于 Spring Boot + 微服务以及前后端分离等全栈技术, 定期视频教程分享, 关注后回复 Java , 领取松哥为你精心准备的 Java 干货!
来源: https://www.cnblogs.com/lenve/p/11696717.html