avatar

@ControllerAdvice的使用

处理全局异常


我们使用fileupload项目来进行测试,首先我们设置上传文件的大小限制

1
spring.servlet.multipart.max-file-size=1KB

测试一下,我们可以看到出现了FileSizeLimitExceededException,同时还有一个提示信息This application has no explicit mapping for /error, so you are seeing this as a fallback. 那么我们如何自定义一个错误提示呢?我们创建一个MyException类

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
26
27
28
package com.example.fileupload;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
* @author: WJZheng
* @date: 2020/3/16 16:31
* @description:
*/
@ControllerAdvice
public class MyException {

@ExceptionHandler(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();
}
}

我们再来做一次文件上传,我们可以看到自定义的错误提示了

那么如果我们想自定义一个错误页面呢?首先我们添加thymeleaf依赖,然后添加一个方法

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
26
27
28
29
30
31
32
33
34
35
36
package com.example.fileupload;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
* @author: WJZheng
* @date: 2020/3/16 16:31
* @description:
*/
@ControllerAdvice
public class MyException {

// @ExceptionHandler(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();
// }

@ExceptionHandler(MaxUploadSizeExceededException.class)
public ModelAndView myException(MaxUploadSizeExceededException e) throws IOException {
ModelAndView modelAndView = new ModelAndView("error");
modelAndView.addObject("error","上传文件大小超出限制");
return modelAndView;
}
}

然后在template目录下创建一个error.html文件

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>
<h1 th:text="${error}"></h1>
</body>
</html>

上传一个超出1KB的文件后就会看到自定义的错误提示页面了

预设全局数据


我们先创建一个GlobalData类,该类定义了一个全局数据,即任意一个Controller都可以获取到

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
26
package com.example.controlleradvice;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;

import java.util.HashMap;
import java.util.Map;

/**
* @author: WJZheng
* @date: 2020/3/16 16:48
* @description:
*/

@ControllerAdvice
public class GlobalData {

//这里的key就是info,value就是该方法的返回值
@ModelAttribute(value = "info")
public Map<String,Object> myData() {
Map<String, Object> map = new HashMap<>();
map.put("name","WJZheng");
map.put("address","https://wellenzheng.github.io/");
return map;
}
}

然后我们创建一个Controller,通过Model来获取数据并在控制台输出

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
26
27
package com.example.controlleradvice;

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;
import java.util.Set;

/**
* @author: WJZheng
* @date: 2020/3/16 16:51
* @description:
*/

@RestController
public class DataController {
@GetMapping("/data")
public String data(Model model) {
Map<String, Object> map = model.asMap();
Set<String> keySet = map.keySet();
for (String key : keySet) {
System.out.println(key + ":" + map.get(key));
}
return "data";
}
}

请求参数预处理


我们首先创建一个Book类和一个Author类,他们都有一个同名的属性name。

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.example.controlleradvice;

/**
* @author: WJZheng
* @date: 2020/3/16 17:04
* @description:
*/
public class Book {
private String id;
private String name;
private Double price;

@Override
public String toString() {
return "Book{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", price=" + price +
'}';
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Double getPrice() {
return price;
}

public void setPrice(Double price) {
this.price = price;
}
}
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
26
27
28
29
30
31
32
33
34
35
package com.example.controlleradvice;

/**
* @author: WJZheng
* @date: 2020/3/16 17:05
* @description:
*/
public class Author {
private String name;
private Integer age;

@Override
public String toString() {
return "Author{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}
}

然后在Controller里添加一个方法来post数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.example.controlleradvice;

import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* @author: WJZheng
* @date: 2020/3/16 17:05
* @description:
*/

@RestController
public class BookController {
@PostMapping("/book")
public void addBook(@ModelAttribute("book") Book book, @ModelAttribute("author") Author author){ //@ModelAttribute是为参数创建一个别名
System.out.println(book);
System.out.println(author);
}
}

最后在GlobalData中为这两个参数绑定一个前缀

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
26
27
28
29
package com.example.controlleradvice;

import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;

import java.util.HashMap;
import java.util.Map;

/**
* @author: WJZheng
* @date: 2020/3/16 16:48
* @description:
*/

@ControllerAdvice
public class GlobalData {

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

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

然后在postman中进行测试,我们就可以在提交的数据中加上前缀来区别这两个类的同名属性

若未加预处理之前,springboot会把两个同名属性合并在一起

Author: WJZheng
Link: https://wellenzheng.github.io/2020/03/16/ControllerAdvice%E7%9A%84%E4%BD%BF%E7%94%A8/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.

Comment