Spring Boot之@ControllerAdvice

  • @ControllerAdvice就是@Controller增强版
  • @ControllerAdvice主要用来处理全局数据,一般搭配@ExceptionHandler@ModelAttribute@InitBinder使用

全局异常处理

方法的参数可以有异常实例,HttpServletRequestHttpServletResponseModel

方法的返回值可以是一段JSON,一个ModelAndView,一个逻辑视图名等

  1. 直接处理
1
2
3
4
5
6
7
8
9
10
11
12
@ControllerAdvice
public class CustomExceptionHandler {

@ExceptionHandler(MaxUploadSizeExceededException.class)
public void uploadException(MaxUploadSizeExceededException e, HttpServletResponse response) throws IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.write("上传文件大小超出限制!");
out.flush();
out.close();
}
}
  1. 返回ModelAndView
1
2
3
4
5
6
7
8
9
10
11
12
// 1.设置全局异常处理
@ControllerAdvice
public class CustomExceptionHandler2 {

@ExceptionHandler(MaxUploadSizeExceededException.class)
public ModelAndView uploadException(MaxUploadSizeExceededException e) throws IOException {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", "上传文件大小超出限制...");
modelAndView.setViewName("error");
return modelAndView;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 2.导入thymeleaf依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- 3.resource目录下的templates目录下添加error.html -->
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div th:text="${msg}"></div>
</body>
</html>

添加全局数据

  1. 添加全局数据
1
2
3
4
5
6
7
8
9
10
11
@ControllerAdvice
public class GlobalConfig {

@ModelAttribute(value = "info")
public Map<String,String> userInfo() {
HashMap<String, String> map = new HashMap<>();
map.put("author", "罗贯中");
map.put("gender", "男");
return map;
}
}
  1. 取出全局数据
1
2
3
4
5
6
7
8
9
10
11
@GetMapping("/hello")
public void hello(Model model) {
Iterator<Map.Entry<String, Object>> iterator = model.asMap().entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<String, Object> map = iterator.next();
String key = map.getKey();
Object value = map.getValue();
System.out.println(key + ": " + value);
//info: {gender=男, author=罗贯中}
}
}

请求参数预处理

@ControllerAdvice结合@InitBinder还能实现请求参数预处理,即将表单中的数据绑定到实体类上进行一些额外处理。

  1. 参数传递时,两个实体类的name属性混淆
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Author {
private String name;
private int age;
//setter getter...
}

public class Book {
private String name;
private String author;
//setter getter...
}

@GetMapping("/book")
@ResponseBody
public String book(Book book, Author author) {
return book.toString() + ">>>" + author.toString();
}

//请求:http://localhost:8080/book?name=张三&age=18&name=三国演义&author=罗贯中
//返回数据:Book{name='张三,三国演义', author='罗贯中'}>>>Author{name='张三,三国演义', age=18}
  1. 参数预处理,解决两个Bean同名属性混淆
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 1.将Controller方法参数通过@ModelAttribute("a")绑定属性a和b
@GetMapping("/book")
@ResponseBody
public String book(@ModelAttribute("b") Book book, @ModelAttribute("a") Author author){
return book.toString() + ">>>" + author.toString();
}

// 2.1在ControllerAdvice中用@InitBinder("a")来表示处理@ModelAttribute("a")中的参数
// 2.2通过WebDateBinder来设置字段前缀
@ControllerAdvice
public class GlobalConfig2 {

@InitBinder("b")
public void init(WebDataBinder binder) {
binder.setFieldDefaultPrefix("b.");
}

@InitBinder("a")
public void init2(WebDataBinder binder) {
binder.setFieldDefaultPrefix("a.");
}
}

//请求:http://localhost:8080/book?a.name=张三&a.age=18&b.name=三国演义&b.author=罗贯中
//返回数据:Book{name='三国演义', author='罗贯中'}>>>Author{name='张三', age=18}