@ControllerAdvice 用法
Posted 探索er
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了@ControllerAdvice 用法相关的知识,希望对你有一定的参考价值。
@ControllerAdvice 用法
顾名思义,@ControllerAdvice就是@Controller 的增强版。@ControllerAdvice主要用来处理全局数据,一般搭配@ExceptionHandler、@ModelAttribute以及@InitBinder使用。
全局异常处理
@ControllerAdvice最常见的使用场景就是全局异常处理。比如文件上传大小限制的配置,如果用户上传的文件超过了限制大小,就会抛出异常,此时可以通过@ControllerAdvice结合@ExceptionHandler定义全局异常捕获机制,代码如下:
@ControllerAdvice
public class CustomExceptionHandler
@ExceptionHandler(MaxUploadSizeExceededException.class)
public void uploadException(MaxUploadSizeExceededException e, HttpServletResponse resp) throws IOException
resp.setContentType("text/html;charset=utf-8");
System.out.println(1111);
PrintWriter out = resp.getWriter();
out.write("上传文件大小超出限制!");
out.flush();
out.close();
只需在系统中定义CustomExceptionHandler类,然后添加@ControllerAdvice注解即可。当系统启动时,该类就会被扫描到Spring容器中,然后定义uploadException方法,在该方法上添加了@ExceptionHandler注解,其中定义的MaxUploadSizeExceededException.class 表明该方法用来处理MaxUploadSizeExceededException类型的异常。如果想让该方法处理所有类型的异常,只需将MaxUploadSizeExceededException改为 Exception即可。方法的参数可以有异常实例、HttpServletResponse以及HttpServletRequest、Model 等,返回值可以是一段JSON、一个ModelAndView、一个逻辑视图名等。此时,上传一个超大文件会有错误提示给用户。
如果返回参数是一个ModelAndView,假设使用的页面模板为Thymeleaf(注意添加Thymeleaf相关依赖),此时异常处理方法定义如下:
@ControllerAdvice
public class CustomExceptionHandler
@ExceptionHandler(MaxUploadSizeExceededException.class)
public ModelAndView uploadException(MaxUploadSizeExceededException e) throws IOException
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "上传文件大小超出限制! ");
mv.setViewName("error");
return mv;
然后在resources/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>
此时上传出错效果一致。
添加全局数据
@ControllerAdvice是一个全局数据处理组件,因此也可以在@ControllerAdvice中配置全局数据,使用@ModelAttribute注解进行配置,代码如下:
@ControllerAdvice
public class GlobalConfig
@ModelAttribute(value = "info")
public Map<String, String> userInfo()
HashMap<String, String> map = new HashMap<>();
map.put("username", "罗贯中");
map.put("gender", "男");
return map;
代码解释:
- 在全局配置中添加userInfo方法,返回一个map。该方法有一个注解@ModelAttribute,其中的value属性表示这条返回数据的key,而方法的返回值是返回数据的value。
- 此时在任意请求的Controller 中,通过方法参数中的Model都可以获取info 的数据。
Controller 例代码如下:
public class MyController
@GetMapping("/hello")
@ResponseBody
public void hello(Model model)
Map<String, Object> map = model.asMap();
Set<String> keySet = map.keySet();
Iterator<String> iterator = keySet.iterator();
while (iterator.hasNext())
String key = iterator.next();
Object value = map.get(key);
System.out.println(key + ">>>>>" + value);
在请求方法中,将Model 中的数据打印出来,如图所示。
请求参数预处理
@ControllerAdvice结合@InitBinder还能实现请求参数预处理,即将表单中的数据绑定到实体类上时进行一些额外处理。
例如有两个实体类 Book和 Author,代码如下:
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
@ToString
public class Book
private String name;
private String author;
@JsonIgnore//一般标记在属性或者方法上,返回的json数据即不包含该属性
private Float price;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date publicationDate;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Author
private String name;
private int age;
在 Controller 上需要接收两个实体类的数据,Controller 中的方法定义如下:
@ControllerAdvice
public class GlobalConfig1
@InitBinder("b")
public void init(WebDataBinder binder)
binder.setFieldDefaultPrefix("b.");
@InitBinder("a")
public void init2(WebDataBinder binder)
binder.setFieldDefaultPrefix("a.");
代码解释:
- 在 GlobalConfig类中创建两个方法,第一个@InitBinder(“b”)表示该方法是处理@ModelAttribute(“b”)对应的参数的,第二个@InitBinder(“a”)表示该方法是处理@ModelAttribute(“a”)对应的参数的。
- 在每个方法中给相应的 Field设置一个前缀,然后在浏览器中请求http:/ocalhost:8080/book?b.name=三国演义&b.author=罗贯中&a.name=曹雪芹&a.age=48,即可成功地区分出name属性。
- 在WebDataBinder对象中,还可以设置允许的字段、禁止的字段、必填字段以及验证器等。
ld设置一个前缀,然后在浏览器中请求http:/ocalhost:8080/book?b.name=三国演义&b.author=罗贯中&a.name=曹雪芹&a.age=48,即可成功地区分出name属性。
- 在WebDataBinder对象中,还可以设置允许的字段、禁止的字段、必填字段以及验证器等。
spring boot中@ControllerAdvice的用法
@ControllerAdvice ,这是一个增强的 Controller。使用这个 Controller ,可以实现三个方面的功能:
- 全局异常处理
- 全局数据绑定
- 全局数据预处理
灵活使用这三个功能,可以帮助我们简化很多工作,需要注意的是,这是 SpringMVC 提供的功能,在 Spring Boot 中可以直接使用,下面分别来看。
全局异常处理
使用 @ControllerAdvice 实现全局异常处理,只需要定义类,添加该注解即可定义方式如下:
@ControllerAdvice public class MyGlobalExceptionHandler { @ExceptionHandler(Exception.class) public ModelAndView customException(Exception e) { ModelAndView mv = new ModelAndView(); mv.addObject("message", e.getMessage()); mv.setViewName("myerror"); return mv; } }
@ExceptionHandler 注解用来指明异常的处理类型,即如果这里指定为 NullpointerException,则数组越界异常就不会进到这个方法中来。在该类中,可以定义多个方法,不同的方法处理不同的异常,例如专门处理空指针的方法、专门处理数组越界的方法…,也可以直接向上面代码一样,在一个方法中处理所有的异常信息。
全局数据绑定
全局数据绑定功能可以用来做一些初始化的数据操作,我们可以将一些公共的数据定义在添加了 @ControllerAdvice 注解的类中,这样,在每一个 Controller 的接口中,就都能够访问导致这些数据。
使用步骤,首先定义全局数据,如下:
@ControllerAdvice public class MyGlobalExceptionHandler { @ModelAttribute(name = "md") public Map<String,Object> mydata() { HashMap<String, Object> map = new HashMap<>(); map.put("age", 99); map.put("gender", "男"); return map; } }
定义完成后,在任何一个Controller 的接口中,都可以获取到这里定义的数据:使用 @ModelAttribute 注解标记该方法的返回数据是一个全局数据,默认情况下,这个全局数据的 key 就是返回的变量名,value 就是方法返回值,当然开发者可以通过 @ModelAttribute 注解的 name 属性去重新指定 key。
@RestController public class HelloController { @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"; } }
全局数据预处理
考虑我有两个实体类,Book 和 Author,分别定义如下:
public class Book { private String name; private Long price; //getter/setter } public class Author { private String name; private Integer age; //getter/setter }
此时,如果我定义一个数据添加接口,如下:
@PostMapping("/book") public void addBook(Book book, Author author) { System.out.println(book); System.out.println(author); }
这个时候,添加操作就会有问题,因为两个实体类都有一个 name 属性,从前端传递时 ,无法区分。此时,通过 @ControllerAdvice 的全局数据预处理可以解决这个问题
解决步骤如下:
1.给接口中的变量取别名
@PostMapping("/book") public void addBook(@ModelAttribute("b") Book book, @ModelAttribute("a") Author author) { System.out.println(book); System.out.println(author); }
2.进行请求数据预处理
在 @ControllerAdvice 标记的类中添加如下代码:
@InitBinder("b") public void b(WebDataBinder binder) { binder.setFieldDefaultPrefix("b."); } @InitBinder("a") public void a(WebDataBinder binder) { binder.setFieldDefaultPrefix("a."); }
@InitBinder(“b”) 注解表示该方法用来处理和Book和相关的参数,在方法中,给参数添加一个 b 前缀,即请求参数要有b前缀.
3.发送请求
请求发送时,通过给不同对象的参数添加不同的前缀,可以实现参数的区分.
原文链接:https://www.javaboy.org/2019/0422/springmvc-controlleradvice.html 江南一点雨
以上是关于@ControllerAdvice 用法的主要内容,如果未能解决你的问题,请参考以下文章
Spring中通过java的@Valid注解和@ControllerAdvice实现全局异常处理。
一网打尽 @ExceptionHandlerHandlerExceptionResolver@controlleradvice 三兄弟!