07.SpringBoot之@ControllerAdvice

SpringBoot之@ControllerAdvice

@ControllerAdvice

@ControllerAdvice 注解有以下三个方面的作用:

  1. 处理全局异常
  2. 预设全局数据
  3. 请求参数预处理

异常处理

进行异常处理,我们在捕捉到指定的异常之后,可以跳转到指定的页面或是返回响应的数据,这里以跳转页面为例。错误页面如下:

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 {
/**
* 文件大小超过限制的异常处理
* @param e
*/
@ExceptionHandler(value = {MaxUploadSizeExceededException.class})
public ModelAndView myException(MaxUploadSizeExceededException e) throws IOException {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("error","上传文件大小超过限制");
modelAndView.setViewName("myerror");
return modelAndView;
}

/*@ExceptionHandler(value = {MaxUploadSizeExceededException.class})
public void myException(MaxUploadSizeExceededException e, HttpServletResponse response) throws IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.write("上传文件大小超出限制");
writer.flush();
writer.close();
}*/
}

上面的两种方式分别以定制错误页面和返回数据为示例。

预设全局数据

预设全局数据,其实就是在某一个地方定义好数据之后,其他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.");
}
}

此时我们测试时,前端传的数据就需要改变一下。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×