ControllerAdvice 注解的三种使用场景

Posted by 彭楷淳 on 2021-01-15
Estimated Reading Time 3 Minutes
Words 782 In Total
Viewed Times

@ControllerAdvice,顾名思义,这是一个增强的 Controller。使用这个 Controller ,可以实现三个方面的功能:

  1. 全局异常处理
  2. 全局数据绑定
  3. 全局数据预处理

全局异常处理


使用 @ControllerAdvice 实现全局异常处理,只需要定义类,添加该注解即可定义方式如下:

1
2
3
4
5
6
7
8
9
10
11
@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 的接口中,就都能够访问导致这些数据。使用步骤,首先定义全局数据,如下:

1
2
3
4
5
6
7
8
9
10
11
@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 的接口中,都可以获取到这里定义的数据:

1
2
3
4
5
6
7
8
9
10
@RestController
public class HelloController {

@GetMapping("/hello")
public String hello(Model model) {
Map<String, Object> map = model.asMap();
System.out.println(map);
return "Hello ControllerAdvice";
}
}

全局数据预处理


比如现两个实体类,Book 和 Author,分别定义如下:

1
2
3
4
5
6
public class Book {

private String name;
private Long price;
// 省略 getter/setter
}
1
2
3
4
5
6
public class Author {

private String name;
private Integer age;
// 省略 getter/setter
}

此时,如果我定义一个数据添加接口,如下:

1
2
3
4
5
6
@PostMapping("/book")
public void addBook(Book book, Author author) {

System.out.println(book);
System.out.println(author);
}

这个时候,添加操作就会有问题,因为两个实体类都有一个 name 属性,从前端传递时 ,无法区分。此时,通过 @ControllerAdvice 的全局数据预处理可以解决这个问题。解决步骤如下:

1. 给接口中的变量取别名

1
2
3
4
5
@PostMapping("/book")
public void addBook(@ModelAttribute("b") Book book, @ModelAttribute("a") Author author) {
System.out.println(book);
System.out.println(author);
}

2. 进行请求数据预处理
@ControllerAdvice 标记的类中添加如下代码:

1
2
3
4
5
6
7
8
@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. 前缀。

更多干货请移步:https://antoniopeng.com


If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !