SpringMVC解析

1 SpringMVC执行流程

image.png

简单流程:
1 前端发起web请求
2 dispatchServlet收到请求,转发到对应的controller
3 controller处理业务逻辑,将处理结果或页面返回给dispatchServlet
4 dispatchServlet再将结果转发到视图解析器view
5 视图解析器解析结果返回到web端

image.png

详细流程:
1 前端发起web请求
2 dispatchServlet收到请求,基于handlerMapping地址映射,找到对应的handler(控制器,即controller)
3 基于handler找对应的handlerAdapter,调用handler方法返回ModelaAndView
4 利用viewResolver,通过返回的ModelAndView找到对应的view视图解析器
5 解析视图,response返回结果到web端

2 springmvc组件

2.1 HandlerMapping

HandlerMapping即url映射,根据web端的地址找到处理该请求的控制器,就是HandlerMapping做的事。通过HandlerMapping继承树,可以发现有三个子类。

  • SimpleUrlHandlerMapping:需手动配置映射关系。
<bean name="simpleControl" class="com.control.SimpleControl"/>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="urlMap">
            <props>
                <prop key="/hello.do">simpleControl</prop>
            </props>
        </property>
</bean>
  • BeanNameUrlHandlerMapping:根据配置的beanname自动从映射关系中找到controller。
    <bean name="simpleControl" class="com.control.SimpleControl"/>

  • RequestMappingHandlerMapping:我们工作中最常用的,通过@RequestMapping映射。这里不做举例。

springmvc中默认配置的是BeanNameUrlHandlerMapping。前两个是类映射,RequestMappingHandlerMapping是方法映射。

注意:
1 如果自己配置了HandlerMapping,那么默认的就不生效了
2 可以配置多个HandlerMapping。如果配置了多个HandlerMapping,且urlname一样,那么会根据HandlerMapping的order排序值选择HandlerMapping

2.2 HandlerAdapter

HandlerAdapter即适配器,每个Handler都对应一个适配器来调用handler。


HandlerAdapter.jpg

springmvc默认配置了SimpleControllerHandlerAdapter和HttpRequestHandlerAdapter

2.3 Handler

Handler可以理解为controller,即控制器,用于处理业务逻辑,返回ModelAndView。Handler具体实现有以下四种。

  • Controller
public class TestController implements Controller {
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ModelAndView modelAndView = new ModelAndView("userView");
        modelAndView.addObject("name","小明");
        return modelAndView;
    }
}
  • HttpRequestHandler
public class TestHttpRequestHandler implements HttpRequestHandler {
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().println("666");
    }
}
  • HttpServlet
public class TestHttpServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("666");
    }
}

在使用HttpServlet时,必须配置一个对应的适配器。因为springmvc默认配置的适配器是上面两个handler对应的适配器。

<bean class="org.springframework.web.servlet.handler.SimpleServletHandlerAdapter"/>

  • @RequestMapping注解(常用的,此处不举例了)
2.4 ViewResolver

ViewResolver是用来管理视图解析器view的。ViewResolver中只有一个方法。根据viewName找到view。

View resolveViewName(String viewName, Locale locale) throws Exception;

ViewResolver有三个常用的实现类:

  • BeanNameViewResolver 根据名称找到对应的View
<bean name="myView" class="com.control.MyView"/>
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
public class TestController implements Controller {
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ModelAndView modelAndView = new ModelAndView("myView");
        modelAndView.addObject("name","小明");
        return modelAndView;
    }
}
public class MyView implements View {

    public String getContentType() {
        return null;
    }

    public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
          //model.get("name")就是controller中设置的属性
        response.getWriter().println(model.get("name"));
    }
}
  • InternalResourceViewResolver
    这是springmvc默认配置的ViewResolver,也可手动修改配置,添加前后缀。
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/page/"/>
        <property name="suffix" value=".jsp"/>
        <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/>
</bean>
  • AbstractTemplateViewResolver
    包括FreeMarkerViewResolver和GroovyMarkupViewResolver。没怎么用过,这里不做举例了。
2.5 View

View就是视图解析器,作用是对ModelAndView中的数据解析,通过Response返回到web端。实现View接口,重写render方法,就能自定义一个视图解析器

void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
2.6 HandlerExceptionResolver

HandlerExceptionResolver即异常处理器,用于处理整个springmvc执行流程中出现的异常。

2.6.1 常用的有三个异常处理器:

springmvc默认配置的是DefaultHandlerExceptionResolver和ResponseStatusExceptionResolver

  • DefaultHandlerExceptionResolver
    根据传入的Exception异常参数判断是哪种具体的异常来进行相应的处理返回。‘

  • ResponseStatusExceptionResolver
    根据异常类型上面的@ResponseStatus注解的code和reason参数,
    返回对应的错误信息

@ResponseStatus(code = HttpStatus.GATEWAY_TIMEOUT, reason = "访问超时")
public class ResponseStatusException extends RuntimeException {
    public ResponseStatusException() {
    }

    public ResponseStatusException(String message) {
        super(message);
    }
}
public class TestController implements Controller {
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ModelAndView modelAndView = new ModelAndView("myView");
        //这边强制抛出一个ResponseStatusException,测试用
        if(true){
            throw new ResponseStatusException();
        }

        modelAndView.addObject("name","小明");
        return modelAndView;
    }
}
<bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"/>

虽然springmvc默认配置了这个ResponseStatusExceptionResolver,但还是要自己配置一下,因为这里自定义了一个异常,所以默认的配置无法生效。

这时,web端访问这个TestController对应的url,就会出现504异常GATEWAY_TIMEOUT

  • SimpleMappingExceptionResolver
    将异常和异常处理页面绑定,如果出现异常就跳转到绑定页面
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <!--默认的异常处理页面-->
        <property name="defaultErrorView" value="error"/>
        <!--默认的异常状态码-->
        <property name="defaultStatusCode" value="500"/>
        <!--异常与页面对应关系配置-->
        <property name="exceptionMappings">
            <map>
                <entry key="java.lang.RuntimeException" value="error"/>
                <entry key="java.lang.IllegalArgumentException" value="argumentError"/>
            </map>
        </property>
    </bean>
2.6.2 自定义异常处理器

实现HandlerExceptionResolver接口,并重写resolveException方法。

public class SimpleExceptionHandle implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ModelAndView modelAndView = new ModelAndView("error");
        modelAndView.addObject("message", ex.getMessage());
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        //将异常信息通过打印流打印到输出流out中
        ex.printStackTrace(new PrintStream(out, true));
        modelAndView.addObject("stack", out.toString());
        return modelAndView;
    }
}

意思就是获取异常信息,打印到输出流中,并放入ModelAndView,通过视图解析器返回到error.jsp页面显示错误信息。

    <bean class="com.study.control.MyExceptionResolver"/>

配置自定义异常处理器。

2.7 HandlerInterceptor

HandlerInterceptor即拦截器。有以下三个方法

  • preHandle 在调用handler方法之前调用。
  • postHandle 在成功调用handler方法后调用。
  • afterCompletion 在调用handler方法之后调用。即使在调用handler方法时出现异常,也会调用afterCompletion。如果没有异常,则顺序在postHandle之后。

自定义拦截器示例:

public class SimpleHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) throws Exception {

        System.out.println("postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
}

配置拦截器:

<mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.control.SimpleHandlerInterceptor"/>
        </mvc:interceptor>
</mvc:interceptors>

可以定义多个拦截器,形成一个拦截器链,比如在handler方法之前会依此遍历拦截器链,依此调用所有拦截器的preHandle方法。

注:异常处理器不是所有配置的都执行。如果在异常处理器的resolveException中返回ModelAndView,表示异常已经被这个异常处理器处理了;如果返回null,表示没有处理,会去找下一个异常处理器处理。
而拦截器则是所有配置的拦截器都会执行。

3 springmvc执行流程源码解析

springmvc执行流程的核心就是DispatcherServlet的doDispatch方法。
下面就拿@RequestMapping方式来解析。

1 注册handler

HandlerMapping可以根据url来找到对应的handler,那么这些对应关系是怎么注册的呢?

protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
          //校验
        Assert.notNull(urlPath, "URL path must not be null");
        Assert.notNull(handler, "Handler object must not be null");
        Object resolvedHandler = handler;

        // 如果是懒加载的,就存handler的名字
        if (!this.lazyInitHandlers && handler instanceof String) {
            String handlerName = (String) handler;
            if (getApplicationContext().isSingleton(handlerName)) {
                          // 从spring容器中根据beanname获取bean
                resolvedHandler = getApplicationContext().getBean(handlerName);
            }
        }
            // url跟handler对应关系保存在handerMap中
        Object mappedHandler = this.handlerMap.get(urlPath);
        if (mappedHandler != null) {
            if (mappedHandler != resolvedHandler) {
                throw new IllegalStateException(
                        "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
                        "]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
            }
        }
        else {
                // 如果url是/,那么设置这个handler是根handler
            if (urlPath.equals("/")) {
                if (logger.isInfoEnabled()) {
                    logger.info("Root mapping to " + getHandlerDescription(handler));
                }
                setRootHandler(resolvedHandler);
            }
      //如果url是/*,那么设置这个handler为默认的handler,所有找不到对应关系的都找这个handler
            else if (urlPath.equals("/*")) {
                if (logger.isInfoEnabled()) {
                    logger.info("Default mapping to " + getHandlerDescription(handler));
                }
                setDefaultHandler(resolvedHandler);
            }
            else {
                        // 将url作为key,handler作为value,存在handlerMap中
                this.handlerMap.put(urlPath, resolvedHandler);
                if (logger.isInfoEnabled()) {
                    logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
                }
            }
        }
    }
2 doDispatch方法
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 {
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);

                // 获取handler
                mappedHandler = getHandler(processedRequest);
                   //如果没有获取到,抛错
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // 获取处理这个handler的适配器
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // Process last-modified header, if supported by the handler.
                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;
                    }
                }
                  // 执行拦截器的preHandle方法
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                // 通过适配器调用handle方法处理业务逻辑
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                      //如果没指定viewName,设置一个默认的viewName
                applyDefaultViewName(processedRequest, mv);
                    //执行拦截器的postHandle方法
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                            //上面所有的异常都只是抛出,没处理,这里才是捕获异常
                dispatchException = ex;
            }
            catch (Throwable err) {
                // err错误
                dispatchException = new NestedServletException("Handler dispatch failed", err);
            }
                // 视图解析器处理modelAndView,通过response返回数据给web端
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            triggerAfterCompletion(processedRequest, response, mappedHandler,
                    new NestedServletException("Handler processing failed", err));
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                // 不管是否出错,都会最后执行拦截器的afterCompletion方法
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                // Clean up any resources used by a multipart request.
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }

执行过程:
1 根据HandlerMapping获取handler链
2 根据handler获取对应的适配器
3 执行拦截器的preHandle方法
4 通过适配器,调用handle方法处理业务逻辑
5 如果没有异常,执行拦截器的postHandle方法
6 不管有没有异常,执行拦截器的afterCompletion方法
7 视图解析器处理modelAndView,通过response返回数据给web端

3.2.1 getHandler

获取handler链

    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
          //遍历1中的handlerMapping,找handler
        for (HandlerMapping hm : this.handlerMappings) {
            if (logger.isTraceEnabled()) {
                logger.trace(
                        "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
            }
              //获取HandlerExecutionChain,并不是返回Handler,因为里面还包含拦截器链 
            HandlerExecutionChain handler = hm.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
        return null;
    }
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
          // 获取handler,因为是@RequestMaping,所以这里获取HandlerMethod
        Object handler = getHandlerInternal(request);
        if (handler == null) {
            handler = getDefaultHandler();
        }
        if (handler == null) {
            return null;
        }
        // 如果是懒加载,那么根据之前注册时存的handlerName获取handler
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }
                  // 将handler和所有拦截器封装成一个handler链
        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
        if (CorsUtils.isCorsRequest(request)) {
            CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
            CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
            CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
            executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
        }
        return executionChain;
    }
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
            // 获取url路径
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        if (logger.isDebugEnabled()) {
            logger.debug("Looking up handler method for path " + lookupPath);
        }
        this.mappingRegistry.acquireReadLock();
        try {
              // 获取执行业务逻辑的方法
            HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
            if (logger.isDebugEnabled()) {
                if (handlerMethod != null) {
                    logger.debug("Returning handler method [" + handlerMethod + "]");
                }
                else {
                    logger.debug("Did not find handler method for [" + lookupPath + "]");
                }
            }
            return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
        }
        finally {
            this.mappingRegistry.releaseReadLock();
        }
    }
3.2.2 getHandlerAdapter

获取handler对应的适配器

    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");
    }
3.2.3 applyPreHandle

调用所有拦截器的preHandle方法

    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for (int i = 0; i < interceptors.length; i++) {
                HandlerInterceptor interceptor = interceptors[i];
                  // 如果前置拦截返回false,就调用后置拦截,然后直接返回到web端,不执行业务逻辑了
                if (!interceptor.preHandle(request, response, this.handler)) {
                    triggerAfterCompletion(request, response, null);
                    return false;
                }
                this.interceptorIndex = i;
            }
        }
        return true;
    }
3.2.4 handle

通过适配器调用handle方法,执行业务逻辑
因为这里是@RequestMapping,所以进入RequestMappingHandlerAdapter的invokeHandlerMethod方法

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        try {
            WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
            ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
                // 设置一个方法执行器
            ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
              //设置参数处理器         invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        //设置返回值处理器  invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
            invocableMethod.setDataBinderFactory(binderFactory);
        // 设置参数名字处理器,可以根据请求参数中名字,自动对应到handler的目标方法的参数名字 invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

            ModelAndViewContainer mavContainer = new ModelAndViewContainer();
            mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
            modelFactory.initModel(webRequest, mavContainer, invocableMethod);
            mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

            AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
            asyncWebRequest.setTimeout(this.asyncRequestTimeout);

            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
            asyncManager.setTaskExecutor(this.taskExecutor);
            asyncManager.setAsyncWebRequest(asyncWebRequest);
            asyncManager.registerCallableInterceptors(this.callableInterceptors);
            asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

            if (asyncManager.hasConcurrentResult()) {
                Object result = asyncManager.getConcurrentResult();
                mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
                asyncManager.clearConcurrentResult();
                if (logger.isDebugEnabled()) {
                    logger.debug("Found concurrent result value [" + result + "]");
                }
                invocableMethod = invocableMethod.wrapConcurrentResult(result);
            }
                  // 通过方法执行器调用方法,处理业务逻辑
            invocableMethod.invokeAndHandle(webRequest, mavContainer);
            if (asyncManager.isConcurrentHandlingStarted()) {
                return null;
            }

            return getModelAndView(mavContainer, modelFactory, webRequest);
        }
        finally {
            webRequest.requestCompleted();
        }
    }
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
        // 执行目标方法
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        setResponseStatus(webRequest);

        if (returnValue == null) {
            if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
                mavContainer.setRequestHandled(true);
                return;
            }
        }
        else if (StringUtils.hasText(getResponseStatusReason())) {
            mavContainer.setRequestHandled(true);
            return;
        }

        mavContainer.setRequestHandled(false);
        try {
            this.returnValueHandlers.handleReturnValue(
                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }
        catch (Exception ex) {
            if (logger.isTraceEnabled()) {
                logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
            }
            throw ex;
        }
    }
    public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
        // 获取方法中的参数
        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
        if (logger.isTraceEnabled()) {
            logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
                    "' with arguments " + Arrays.toString(args));
        }
        // 通过反射调用目标方法,获取返回结果ModelAndView
        Object returnValue = doInvoke(args);
        if (logger.isTraceEnabled()) {
            logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
                    "] returned [" + returnValue + "]");
        }
        return returnValue;
    }
3.2.5 applyPostHandle

执行拦截器的中间方法,由于在执行业务方法之后,如果出现异常,拦截器中间方法并不会执行

    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for (int i = interceptors.length - 1; i >= 0; i--) {
                HandlerInterceptor interceptor = interceptors[i];
                interceptor.postHandle(request, response, this.handler, mv);
            }
        }
    }
3.2.6 applyAfterConcurrentHandlingStarted

此方法在finally中,所以不管有没有异常,都会执行这个拦截器的后置方法

3.2.7 processDispatchResult

捕获业务逻辑执行中的异常并在此统一处理,然后视图解析器处理ModelAndView,封装数据,返回给web端

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
            HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {

        boolean errorView = false;

        if (exception != null) {
            if (exception instanceof ModelAndViewDefiningException) {
                logger.debug("ModelAndViewDefiningException encountered", exception);
                mv = ((ModelAndViewDefiningException) exception).getModelAndView();
            }
            else {
                Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
                //处理异常,封装到ModelAndView中
                mv = processHandlerException(request, response, handler, exception);
                errorView = (mv != null);
            }
        }

        // 视图解析器处理ModelAndView
        if (mv != null && !mv.wasCleared()) {
            render(mv, request, response);
            if (errorView) {
                WebUtils.clearErrorRequestAttributes(request);
            }
        }
        else {
            if (logger.isDebugEnabled()) {
                logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
                        "': assuming HandlerAdapter completed request handling");
            }
        }

        if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            // Concurrent handling started during a forward
            return;
        }

        if (mappedHandler != null) {
            mappedHandler.triggerAfterCompletion(request, response, null);
        }
    }
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
        // Determine locale for request and apply it to the response.
        Locale locale = this.localeResolver.resolveLocale(request);
        response.setLocale(locale);

        View view;
        if (mv.isReference()) {
            // 根据viewName从ViewResolver中获取视图解析器
            view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
            if (view == null) {
                throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
                        "' in servlet with name '" + getServletName() + "'");
            }
        }
        else {
            // No need to lookup: the ModelAndView object contains the actual View object.
            view = mv.getView();
            if (view == null) {
                throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
                        "View object in servlet with name '" + getServletName() + "'");
            }
        }

        // Delegate to the View object for rendering.
        if (logger.isDebugEnabled()) {
            logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
        }
        try {
            if (mv.getStatus() != null) {
                response.setStatus(mv.getStatus().value());
            }
                  // 调用view的render方法,处理数据,通过response返回
            view.render(mv.getModelInternal(), request, response);
        }
        catch (Exception ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
                        getServletName() + "'", ex);
            }
            throw ex;
        }
    }

至此SpringMVC的执行流程解析完毕。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,042评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,996评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,674评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,340评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,404评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,749评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,902评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,662评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,110评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,577评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,258评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,848评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,726评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,952评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,271评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,452评论 2 348

推荐阅读更多精彩内容