SpringBoot之@ControllerAdvice
@ControllerAdvice
@ControllerAdvice 注解有以下三个方面的作用:
- 处理全局异常
- 预设全局数据
- 请求参数预处理
异常处理
进行异常处理,我们在捕捉到指定的异常之后,可以跳转到指定的页面或是返回响应的数据,这里以跳转页面为例。错误页面如下:
1 2 3 4 5 6 7 8 9 10
| <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div th:text="${error}"></div> </body> </html>
|
全局异常处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @ControllerAdvice public class MyCustomException {
@ExceptionHandler(value = {MaxUploadSizeExceededException.class}) public ModelAndView myException(MaxUploadSizeExceededException e) throws IOException { ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("error","上传文件大小超过限制"); modelAndView.setViewName("myerror"); return modelAndView; }
}
|
上面的两种方式分别以定制错误页面和返回数据为示例。
预设全局数据
预设全局数据,其实就是在某一个地方定义好数据之后,其他Controller中都可以获取到的。
1 2 3 4 5 6 7 8 9 10
| @ControllerAdvice public class GlobalData { @ModelAttribute(value = "info") public Map<String,Object> myData(){ Map<String,Object> map = new HashMap<>(); map.put("name","hao.yang"); map.put("address","ooyhao.github.io"); return map; } }
|
controller中获取:
1 2 3 4 5 6 7 8
| @GetMapping("/hello") public String hello(Model model){ Map<String, Object> map = model.asMap(); for (Map.Entry<String,Object> ma : map.entrySet()){ System.out.println(ma); } return "hello"; }
|
打印结果:info={address=ooyhao.github.io, name=hao.yang}
请求参数预处理
我们定义两个实体类:
1 2 3 4 5 6 7 8 9 10 11
| @Data public class Book { private String name; private Double price; }
@Data public class Author { private String name; private Integer age; }
|
可以看出,在Book和Author实体中,都有一个相同的属性,为name。编写Controller。
1 2 3 4 5
| @PostMapping("/book") public void addBook(Book book,Author author){ System.out.println(book); System.out.println(author); }
|
此时我们同事使用PostMan测试,结果如下:
测试结果:
可以看出,这样的结果是有问题的,不管Book还是Author的name都是两个值拼接起来的,那么在不改变实体类的情况下保证没有问题呢?
下面我们使用@ControllerAdvice
和 @ModelAttribute
来实现:
首先,修改Controller类:
1 2 3 4 5 6 7 8
| @RestController public class BookController { @PostMapping("/book") public void addBook(@ModelAttribute("b") Book book,@ModelAttribute("a") Author author){ System.out.println(book); System.out.println(author); } }
|
随后,我们利用@ControllerAdvice
和@InitBinder
注解,来按前缀进行指定。定义如下。
1 2 3 4 5 6 7 8 9 10 11
| @ControllerAdvice public class GlobalData { @InitBinder("a") public void initA(WebDataBinder binder){ binder.setFieldDefaultPrefix("a."); } @InitBinder("b") public void initB(WebDataBinder binder){ binder.setFieldDefaultPrefix("b."); } }
|
此时我们测试时,前端传的数据就需要改变一下。