@ControllerAdvice
,是Spring3.2提供的新注解,它是一个Controller
增强器,可对controller
中被 @RequestMapping
注解的方法加一些逻辑处理。最常用的就是异常处理
@ModelAttribute
和@ExceptionHandler
,前者可以往请求的Model里加数据,后者可以接受请求处理方法抛出的异常。但是他们放在控制器(Controller)里的时候,作用范围是有限的,只管当前控制器里的方法。如果你有几百个控制器,在每个控制器里都加上类似的代码,不免有点冗余和费劲儿。Spring框架提供了@ControllerAdvice
注解,帮助你将其应用到所有的控制器上。
Controller Advice字面上意思是“控制器通知”,Advice除了“劝告”、“意见”之外,还有“通知”的意思。你可以将@ModelAttribute
和@ExceptionHandler
标记的方法提取出来,放到一个类里,并将加上@ControllerAdvice
,这样,所有的控制器都可以用了:
因为@ControllerAdvice
被元注解@Component
标记,所以它也是可以被组件扫描扫到并放入Spring容器的。
如果你只想对一部分控制器添加通知,比如某个包下的控制器,可以这样写:
如果你不想把包名写死,不如把包里的某个类传进去,这样包名重构了也不怕:
如果你只想对某几个控制器添加通知,可以这样写:
挺简单的是不是?
通知里的@ModelAttribute
方法会先于控制器里执行。通知里的@ExceptionHandler
方法优先级会低于控制器里的。仔细想想就能明白,局部的要优先于全局的。
控制器通知还有一个兄弟,@RestControllerAdvice
,如果用了它,错误处理方法的返回值不会表示用的哪个视图,而是会作为HTTP body处理,即相当于错误处理方法加了@ResponseBody
注解。
统一异常处理
需要配合@ExceptionHandler
使用。当将异常抛到controller
时,可以对异常进行统一处理,规定返回的json格式或是跳转到一个错误页面,如果都放回JSON格式的数据可以使用@RestControllerAdvice
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 46 47 48 49 50 51 52 53 54 55
| @ControllerAdvice public class MyExceptionHandler {
/** * 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器 * @param binder */ @InitBinder public void initWebBinder(WebDataBinder binder){ //对日期的统一处理 binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd")); //添加对数据的校验 // binder.setValidator(); }
/** * 把值绑定到Model中,使全局@RequestMapping可以获取到该值 * @param model */ @ModelAttribute public void addAttribute(Model model) { model.addAttribute("attribute", "The Attribute"); }
/** * 捕获CustomException * @param e * @return json格式类型 @RestControllerAdvice */ @ResponseBody @ExceptionHandler({CustomException.class}) //指定拦截异常的类型 @ResponseStatus(HttpStatus.NOT_FOUND) //自定义浏览器返回状态码 public Map<String, Object> customExceptionHandler(CustomException e) { Map<String, Object> map = new HashMap<>(); map.put("code", e.getCode()); map.put("msg", e.getMsg()); return map; }
/** * 捕获CustomException 返回一个视图 * @param e * @return 视图 */ // @ExceptionHandler({CustomException.class}) // public ModelAndView customModelAndViewExceptionHandler(CustomException e) { // Map<String, Object> map = new HashMap<>(); // map.put("code", e.getCode()); // map.put("msg", e.getMsg()); // ModelAndView modelAndView = new ModelAndView(); // modelAndView.setViewName("error"); // modelAndView.addObject(map); // return modelAndView; // } }
|
定义异常类对象
1 2 3 4 5 6 7 8 9 10 11
| //自定义异常类 @Data @AllArgsConstructor @NoArgsConstructor public class CustomException extends RuntimeException {
private long code; private String msg;
}
|
controller中测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Controller public class ExceptionTestController {
/** * 关于@ModelAttribute, * 可以使用ModelMap以及@ModelAttribute()来获取参数值。 */ @GetMapping("/one") public String testError(ModelMap modelMap ) { throw new CustomException(123L, "系统发生500异常!" + modelMap.get("attribute")); }
@GetMapping("/two") public String testTwo(@ModelAttribute("attribute") String attribute) { throw new CustomException(324L, "系统发生500异常!" + attribute); } }
|