- DispatcherServlet接收所有请求
- 调用doDispatcher() 方法进行处理
1). getHandler() 根据当前请求地址找到能处理这个请求的目标类(处理器)
2). getHandlerAdapter() 根据当前处理器类拿到能执行这个处理器方法的适配器
3). 使用适配器执行目标方法
4). 目标方法执行完返回一个ModelAndView对象
5). 根据ModelAndView的信息转发到具体页面,并可以在请求域中取出ModelAndView中的模型数据
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 检查是否是文件上传的请求,如果是,那么包装一个新的request
processedRequest = checkMultipart(request);
// 如果不是文件上传请求,该属性为true, 否则为false
multipartRequestParsed = (processedRequest != request);
// 根据当前请求找到哪一个Controller类来处理请求
mappedHandler = getHandler(processedRequest);
// 如果没有找到那个处理器类,这个请求就404,或者抛异常
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 获取能执行这个处理器类中的所有目标方法的适配器 (相当于一个反射工具)
// mappedHandler.getHandler() 返回的就是控制器类
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 获取请求类型
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//适配器执行目标方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 如果目标方法返回值没有视图名,设置一个默认的视图名
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
//转发到目标页面
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
getHandler() 细节: 怎么通过当前请求找到那个控制器类来处理
- gethandler() 返回类型是HandlerExecutionChain 目标处理器的执行链
- HandlerMapping 中维护了一个map,map中存放了请求和处理该请求的控制器类,HandlerMapping 有多个:
- BeanNameUrlHandlerMapping,
- DefaultAnnotationHandlerMapping
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
如何找到目标处理器类的适配器HandlerAdapter
HandlerAdapter用于调用处理器方法,并且为处理器方法提供参数解析、返回值处理等适配工作,使使用者专心于业务逻辑的实现。 HandlerAdapter 共有三种
- HttpRequestHandlerAdapter
- SimpleControllerHandlerAdapter
- AnnotationMethodHandlerAdapter(当前使用)
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
初始化
在spring容器启动时,在初始化容器后,会初始后以下内容:
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
View 和ViewResolver
ViewResolver的作用就是得到View对象
Interceptor
-
实现HandlerInterceptor接口
-
三个方法 preHandler(), postHandler(), afterCompletion()
-
使用mvc:interceptors标签来声明需要加入到SpringMVC拦截器链中的拦截器
<mvc:interceptors> <!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 --> <bean class="com.host.app.web.interceptor.AllInterceptor"/> <mvc:interceptor> <mvc:mapping path="/test/number.do"/> <!-- 定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的 --> <bean class="com.host.app.web.interceptor.LoginInterceptor"/> </mvc:interceptor> </mvc:interceptors>
异常处理
-
使用SimpleMappingExceptionResolver实现异常处理
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 定义默认的异常处理页面,当该异常类型的注册时使用 --> <property name="defaultErrorView" value="error"></property> <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception --> <property name="exceptionAttribute" value="ex"></property> <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常也页名作为值 --> <property name="exceptionMappings"> <props> <prop key="cn.exception.BusinessException">error-business</prop> </property> </bean>
-
实现HandlerException
public class MyExceptionResolver implements HandlerExceptionResolver{ public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { // TODO Auto-generated method stub ModelAndView mav = new ModelAndView(); if(ex instanceof ArithmeticException){ //处理运算异常 mav.setViewName("ae_error"); }else if(ex instanceof NullPointerException){ //处理空指针异常 mav.setViewName("npe_error"); }else{ //处理其他异常 mav.setViewName("error"); } return mav; } }
-
@ExceptionHandler局部异常处理
@Controller public class DemoController { @RequestMapping("/login2.form") public String excute(){ int a = 1/0; return "ok"; } @ExceptionHandler public String handlerExcepting(HttpServletRequest request,Exception ex){ return "he_error"; } }
-
@ControllerAdvice处理全局异常
@ControllerAdvice public class ExceptionControllerAdvice { @ExceptionHandler(Throwable.class) @ResponseBody public Map<String, Object> ajaxError(Throwable error, HttpServletRequest request, HttpServletResponse response) { Map<String, Object> map = new HashMap<String, Object>(); map.put("error", error.getMessage()); return map; } }