@ControllerAdvice is a new annotation provided by Spring 3.2. It is a Controller enhancer that can add some logic to the method annotated by @RequestMapping in the controller. There are three main functions
- The global configuration of the controller can be placed in the same place through the @ControllerAdvice annotation.
- The methods of the class annotated with @ControllerAdvice can be annotated with @ExceptionHandler, @InitBinder, and @ModelAttribute.
- @ExceptionHandler: used to handle exceptions in the controller globally and perform global exception handling
- @InitBinder: Used to set up WebDataBinder, used to automatically bind foreground request parameters to the Model, and preprocess global data.
- @ModelAttribute: The original function is to bind key-value pairs to the Model. Here, global @RequestMapping can get the key-value pairs set here, and global data binding.
- The @ControllerAdvice annotation will be applied to all controller methods annotated with @RequestMapping.
Global exception handling:
Need to cooperate with @ExceptionHandler.
When throwing an exception to the controller, the exception can be handled uniformly, specifying the returned json format or jumping to an error page
/**
* @ClassName:CustomExceptionHandler
* @Description: 全局异常捕获
* @Author:
* @Date: 2020/5/25、13:38
*/
@Slf4j
@ControllerAdvice(annotations = {Controller.class, RestController.class})
public class WebControllerAdvice {
@ResponseBody
@ExceptionHandler
public Map errorHandler(Exception ex) {
Map errorMap = new HashMap();
errorMap.put("code", 400);
//判断异常的类型,返回不一样的返回值
if (ex instanceof MissingServletRequestParameterException) {
errorMap.put("msg", "缺少必需参数:" + ((MissingServletRequestParameterException) ex).getParameterName());
} else if (ex instanceof MyException) {
errorMap.put("msg", "这是自定义异常");
}
return errorMap;
}
Custom exception
/**
* @ClassName:MyException
* @Description: 定义异常
* @Author:
* @Date: 2020/5/25、13:44
*/
public class MyException extends RuntimeException {
private long code;
private String msg;
public MyException(Long code, String msg) {
super(msg);
this.code = code;
this.msg = msg;
}
public MyException(String msg) {
super(msg);
this.msg = msg;
}
}
Test Controller
@RestController
public class TestController {
@RequestMapping("testException")
public String testException() throws Exception{
throw new MissingServletRequestParameterException("name","String");
}
@RequestMapping("testMyException")
public String testMyException() throws MyException{
throw new MyException("i am a myException");
}
Test Results:
{"msg":"缺少必需参数:name","code":400}
{"msg":"这是自定义异常","code":400}
Global data binding
The global data binding function can be used to do some initial data operations. We can define some public data in the class annotated with @ControllerAdvice, so that in the interface of each Controller, you can access the data. . To use the steps, first define the global data as follows:
/**
* @ClassName:MyGlobalDataHandler
* @Description: 全局数据
* @Author:
* @Date: 2020/5/25、14:01
*/
@ControllerAdvice
public class MyGlobalDataHandler {
@ModelAttribute(name = "md")
public Map<String,Object> getGlobalData(){
HashMap<String, Object> map = new HashMap<>();
map.put("age", 99);
map.put("gender", "男");
return map;
}
Use the @ModelAttribute annotation to mark the return data of the method as a global data. By default, the key of this global data is the returned variable name, and the value is the return value of the method. Of course, developers can re-specify through the name attribute of the @ModelAttribute annotation key. After the definition is completed, the data defined here can be obtained in any Controller interface:
@GetMapping("/hello")
public String hello(Model model) {
Map<String, Object> map = model.asMap();
System.out.println(map);
int i = 1 / 0;
return "hello controller advice";
}
operation result
{md={gender=男, age=99}}
2020-05-25 14:04:44.388 - [WARN ] - [org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver:logException:197] - Resolved [java.lang.ArithmeticException: / by zero]
Global data preprocessing
Consider that I have two entity classes, Book and Author, defined as follows:
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Book extends BaseEntity {
private String name;
private Long price;
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Author extends BaseEntity {
private String name;
private Long price;
}
If I define a data adding interface, as follows:
@PostMapping("/book")
public void addBook(Book book, Author author) {
System.out.println(book);
System.out.println(author);
}
At this time, the adding operation will be problematic, because both entity classes have a name attribute, which cannot be distinguished when passed from the front end. At this point, the global data preprocessing of @ControllerAdvice can solve this problem
The solution steps are as follows:
1. Alias the variables in the interface:
@PostMapping("/book")
public void addBook(@ModelAttribute("b") Book book, @ModelAttribute("a") Author author) {
System.out.println(book);
System.out.println(author);
}
2. Perform request data preprocessing
Add the following code to the class marked by @ControllerAdvice:
@InitBinder("b")
public void b(WebDataBinder binder) {
binder.setFieldDefaultPrefix("b.");
}
@InitBinder("a")
public void a(WebDataBinder binder) {
binder.setFieldDefaultPrefix("a.");
}
The @InitBinder("b") annotation indicates that the method is used to process Book and related parameters. In the method, add a b prefix to the parameters, that is, the request parameters must have the b prefix.
3. Send the request
When the request is sent, the parameters can be distinguished by adding different prefixes to the parameters of different objects.
This is my WeChat official account: Program Yuanwei Magazine For more articles, please follow WeChat official account