「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战」。
1、前言
从该注解的名字可以看到,这是一个与切面有关的注解,事实上也是如此,我们都知道切面的注解肯定都有个作用范围,切面类的注解只能对其作用范围内的操作,实现切面操作。那RestCntrollerAdvice的作用范围是什么呢?
2、@RestControllerAdvice注解
上面已经说了,每个切面注解都会有自己的作用范围,这个自然也不例外。RestControllerAdvice的作用范围是:单个项目中所有使用了RequestMapping(像PostMapping底层是使用了RequestMapping注解的也支持)的类都归他管,那归RestControllerAdvice他管了,已经清楚了,RestControllerAdvice这个注解要干什么呢?好像根据他的名字我们只能看到这是一个应用于Controller层的切面注解,其他就看不到了。其实该注解还需要与其他注解配合使用才有意义,单独的使用该注解是没有任何意义的,下面就来介绍下该注解都可以与哪些注解配合使用
2.1 @ExceptionHandler
RestControllerAdvice+ExceptionHandler这两个注解的组合,被用作项目的全局异常处理,笔者目前的项目就是这么用的;一旦项目中发生了异常,就会进入使用了RestControllerAdvice注解类中使用了ExceptionHandler注解的方法,我们可以在这里处理全局异常,将异常信息输出到指定的位置。并对所有的错误信息进行归置,下面是示例代码:
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
//自定义异常处理方法
@ExceptionHandler(WinningException.class)
public Response winningException(WinningException e){
Response response = Response.getErrResponse(e);
return response;
}
//其他异常返回给前端处理
@ExceptionHandler(Exception.class)
public Response otherException(Exception e){
e.printStackTrace();
log.error(e.getMessage());
Response response = Response.getErrResponse(e);
return response;
}
}
解释下这段代码的部分内容,slf4j是日志注解,根据不同的错误类型,并根据每种错误类型编辑文案返回前端,这样其实我们就完成了全局异常信息的控制。RestControllerAdvice+ExceptionHandler这么用就对了。
2.2 InitBinder注解、ModelAttribute注解
这两个注解也是可以与RestControllerAdvice配合使用的,那这两个注解的作用是什么呢?
- InitBinder注解 用于将前端传递的参数进行分别绑定
- ModelAttribute注解 :获取InitBinder绑定的参数,对他进行属性绑定
@Controller
@RequestMapping("/test")
public class TestController {
// 绑定变量名字和属性,参数封装进类
@InitBinder("user")
public void initBinderUser(WebDataBinder binder) {
binder.setFieldDefaultPrefix("user.");
}
// 绑定变量名字和属性,参数封装进类
@InitBinder("addr")
public void initBinderAddr(WebDataBinder binder) {
binder.setFieldDefaultPrefix("addr.");
}
@RequestMapping("/test")
@ResponseBody
public Map<String,Object> test(HttpServletRequest request,@ModelAttribute("user") User user,@ModelAttribute("addr") Addr addr){
Map<String,Object> map=new HashMap<String,Object>();
map.put("user", user);
map.put("addr", addr);
return map;
}
若是不理解,推荐看下这人的博客说的很好:SpringMvc @InitBinder 表单多对象精准绑定接收。
3 ControllerAdvice与RestContollerAdvice
这两个注解猛一看很相似,只是差了一个Rest。那他们有什么相似和区别呢?其实完全可以类比RestController与Controller的区别,RestControllerAdvice=ControllerAdvice+ResponseBody。这样就很清晰了ResponseBody的作用是将返回前端的参数转化成json格式,说白了就是以json数据与前端进行交互。所以ControllerAdvice与RestContollerAdvice的却别就是一个返回给前端的数据是json格式,一个返回的是对象,现在大部分项目前后端交互都是json格式,所以建议都是使用RestControllerAdvice与RestController等注解
4 GlobalExceptionHandler是如何被加载的
ExceptionHandlerExceptionResolver类中实现了InitializingBean接口表面是在启动时初始化ExceptionHandlerExceptionResolver的bean时加载的。
initExceptionHandlerAdviceCache首先从容器中找到所有的带@ControllerAdvice注解的类(@RestControllerAdvice注解是@ControllerAdvice和@ResponseBody组合的注解)。可以看到这里找到了我们自定义的GlobalExceptionHandler。
然后遍历所有adviceBeans,将这些adviceBeans都转换为ExceptionHandlerMethodResolver,转换过程中扫描每个ControllerAdvice中的带@ExceptionHandler注解的方法,再取出这些ExceptionHandler所处理的Exception类型,可能会有多个,然后以exceptionType,为key,method为value放入mappedMethods这个map中进行缓存。
然后将adviceBean放入ExceptionHandlerExceptionResolver的exceptionHandlerAdviceCache这个map中进行缓存。最后exceptionHandlerAdviceCache中的数据如下