1.视图渲染
前面讲到在返回值解析的时候,返回返回值并没有@ResponseBody注解修饰,那么代表的是一个视图的名称,存放在ModelAndView对象中,由springmvc进行转发
接下来看看源码是怎么响应视图的
创建了一个View对象,从之前配置的页面前缀+视图名称+配置的后缀组成一个完成的地址
把响应数据设置到request对象中
最后用Servlet中的RequestDispatcher进行转发
2.全局异常处理
在项目中,后台处理请求之后返回的数据都会包装成固定的格式,比如带状态码,响应描述和数据等等,方便前端同事解析。
那么如果抛出异常的话,我们也希望可以跟正常返回数据一样,将异常信息也包装成统一的格式
这个时候,我们就需要全局异常处理了
未使用全局异常处理之前:
这样的返回信息肯定是对前端不友好的
使用全局异常处理:
使用方式: 往spingmvc中注册一个组件
@ControllerAdvice("包路径")
public class ExceptionHandlerControllerAdvice {
//具体捕获的异常
@ExceptionHandler({Exception.class})
public @ResponseBody String handlerException(Exception e) {
e.printStackTrace();
//在这里可以对异常信息进行包装并返回
return "Exception";
}
}
响应如果
全局异常源码分析:
在视图渲染之前,会对请求结果出现的异常进行处理,并调用到匹配的异常处理方法,返回结果
这里有个异常解析器HandlerExceptionResolverComposite,交由它来处理异常
这个bean同样是在WebMvcConfigurationSupport类用@Bean的方式注册的,然后DispatchServlet在init()方法赋值到了handlerExceptionResolvers变量中
继续跟进具体的处理方法.resolveException
这里会交由ExceptionHandlerExceptionResolver来处理,这个类就是处理异常信息的核心类了
他继承了AbstractHandlerExceptionResolver类,所以这里会到继承而来的父类的resolveException方法中
doResolveHandlerMethodException这个方法是自己实现的,走进来
获取对应异常处理方法
首先就是获取ServletInvocableHandlerMethod。其实就是我们编写的带有@ControllerAdvice异常处理类的对应处理方法
这里有两个容器:
exceptionHandlerCache : 作缓存,controller - ExceptionHandlerMethodResolver
//存放了ControllerAdviceBean 和 处理异常的方法
exceptionHandlerAdviceCache : ControllerAdviceBean - ExceptionHandlerMethodResolver
exceptionHandlerAdviceCache初始化
那么这个exceptionHandlerAdviceCache是什么时候设值的呢。
查看ExceptionHandlerExceptionResolver这个类,实现了InitializingBean接口,在afterPropertiesSet方法中进行设值
初始化ControllerAdviceBean
根据异常找到对应的异常处理方法,
包装成ServletInvocableHandlerMethod 返回
最后就是调用这个异常处理方法,并把返回结果放到ModelAndView,如果是@ResponseBody,就用Response输出
调用逻辑其实和controller方法的处理是一模一样的