SpringMVC源码学习经历(视图解析器篇)

(Notice:以下所有经验也是我根据网上的经验整理的,如有侵权可以联系我删除,欢迎交流和沟通,Wx:IT_Ezra,QQ 654303408。 有问题讨论也可联系我。)

(PS:SpringMVC是目前主流的Web MVC框架之一,其工作流程我在之前的文章中介绍了,下面我想重点讲一下SprignMVC的识图解析器。)

image.png

(PS:我认为最最最核心的流程:下马威)

首先,我们可以根据这个图把整个流程走一遍。首先来了一个请求,然后通过DispatcherServlet,DispatcherServlet的init加载的mapperHandler类的getHandler()方法得到handler,并得到HandlerExecutionChain类,使用HandlerExecutionChain类中的getHandler()方法,遍历HandlerAdapterS集合,找到支持Handler的HandlerAdapter,使用HandlerAdapter。返回ModelAndView, 然后把ModelAndView传到视图解析器(InternalResourceViewResolver)解析,InternalResourceViewResolver继承了UrlBasedViewResolver类,UrlBasedViewResolver类继承AbstractCachingViewResolver抽象类,AbstractCachingViewResolver抽象类会首先createView()方法,其内部调用loadView()方法,loadView()方法里面调用了buildView()方法,然后返回一个InternalResourceView视图。

---------------------------------------------------------------------------

然后开始介绍重要的借口和类。
  • 1.View接口

视图基础接口,它的各种实现是么有状态的,所以也是线程安全的。该接口定义了两个方法。View接口

  • 2. AbstractView抽象类

View接口的基础实现类。我们稍微介绍一下这个抽象类。 AbstractView抽象类
其中非常重要的一个方法render方法,该方法里面有一个抽象方法renderMergedOutputModel方法(AbstractView抽象类定义的抽象方法,为View接口提供的render方法服务)。

render方法

  • 3. AbstractUrlBasedView抽象类

继承自AbstractView抽象类,增加了1个类型为String的url参数。
  • 4. InternalResourceView类(重点类,我们在配置Springmvc的时候经常会看到它的配置)

继承自AbstractUrlBasedView抽象类的类,表示JSP视图。
我们看下这个类的renderMergedOutputModel方法(AbstractView抽象类定义的抽象方法,为View接口提供的render方法服务)。这个抽象类里面可一看到最后决定用include方法还是forward方法。这两个方法都是重定向方法,但是区别不同的是,惟一的不同在于:利用include()方法将HTTP请求转送给其他Servlet后,被调用的Servlet虽然可以处理这个HTTP请求,但是最后的主导权仍然是在原来的Servlet。RequestDispatcher是一个Web资源的包装器,可以用来把当前request传递到该资源,或者把新的资源包括到当前响应中。

renderMergedOutputModel

我们在SpringMVC的配置文件里面,会配置视图解析器,目前主流的就是InternalResourceView类,当然它的实现也是依赖于另一个抽象类AbstractCachingViewResolver(后文会讲到)。我们继续介绍其他类和接口

   <!-- 视图解析器 -->
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 前缀 -->
        <property name="prefix">
            <value>/WEB-INF/</value>
        </property>
        <!-- 后缀 -->
        <property name="suffix">
            <value>.html</value>
        </property>
    </bean>
  • 5. JstlView类

JSTL视图,继承自InternalResourceView,该类大致上与InternalResourceView类一致。
  • 6. AbstractTemplateView抽象类

继承自AbstractUrlBasedView抽象类,重写了renderMergedOutputModel方法,在该方法中会调用renderMergedTemplateModel方法,renderMergedTemplateModel方法为新定义的抽象方法。
该抽象类有几个boolean属性exposeSessionAttributes,exposeRequestAttributes。 设置为true的话会将request和session中的键值和值丢入到renderMergedTemplateModel方法中的model这个Map参数中。
这个类是某些模板引擎视图类的父类。 比如FreemarkerView,VelocityView。
  • 7. ViewResolver接口

视图解释器,用来解析视图View,与View接口配合使用。
该接口只有1个方法,通过视图名称viewName和Locale对象得到View接口实现类:
  • 8. AbstractCachingViewResolver抽象类

带有缓存功能的ViewResolver接口基础实现抽象类,该类有个属性名为viewAccessCache的以 “viewName_locale” 为key, View接口为value的Map。
该抽象类实现的resolveViewName方法内部会调用createView方法,方法内部会调用loadView抽象方法。
  • 9. UrlBasedViewResolver类

继承自AbstractCachingViewResolver抽象类、并实现Ordered接口的类,是ViewResolver接口简单的实现类

AbstractCachingViewResolver

该类复写了createView方法:
createView
父类(AbstractCachingViewResolver)的createView方法内部会调用loadView抽象方法,UrlBasedViewResolver实现了这个抽象方法:

image

image

<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
  <property name="prefix" value="/WEB-INF/view/"/>
  <property name="suffix" value=".jsp"/>
  <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/>
  <property name="viewNames">
    <array>  
      <value type="java.lang.String">*</value>  
    </array>    
  </property>  
  <property name="contentType" value="text/html;charset=utf-8"/>
  <property name="attributesMap">
    <map>
      <entry key="mytest" value="mytestvalue"/>
    </map>
  </property>
  <property name="attributes">
    <props>
      <prop key="test">testvalue</prop>
    </props>
  </property>
</bean>
我们看到:以InternalResourceView这个JSP视图作为视图;viewNames我们设置了*,这里的*代表全部视图名(这个viewNames属性不设置也可以,代表全部视图名都处理);http响应头部contentType信息:text/html;charset=utf-8;attributesMap和attributes传入的Map和Properties参数都会被丢入到staticAttributes属性中,这个staticAttributes会被设置成AbstractView的staticAttributes属性,也就是request域中的参数。

image

image

image

我们看到request域中没有设置mytest和testvalue值。但是页面中会显示,因为我们配置了attributesMap和attributes参数。
如果我们把viewNames中的"*“改成"index1”。那么就报错了,因为处理视图名的时候index匹配不上index1。

image

  • 10. InternalResourceViewResolver类

继承自UrlBasedViewResolver,以InternalResourceView作为视图,若项目中存在“javax.servlet.jsp.jstl.core.Config”该类,那么会以JstlView作为视图。重写了buildView方法,主要就是为了给InternalResourceView视图设置属性
  • 11. ModelAndView对象

顾名思义,带有视图和Model属性的一个模型和视图类。

image

值得注意的是,这个视图属性是一个Object类型的数据,可以直接是View接口的实现类或者视图名(字符串)。

------------------------------------------------------------------

下面我们来分析SpringMVC处理视图的源码。

SpringMVC在处理请求的时候,通过RequestMappingHandlerMapping得到HandlerExecutionChain,然后通过RequestMappingHandlerAdapter得到1个ModelAndView对象,之后通过processDispatchResult方法处理。processDispatchResult方法如下:

image

image

如果配置的ViewResolver如下:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix" value="/WEB-INF/view/"/>
  <property name="suffix" value=".jsp"/>
</bean>

那么就是使用InternalResourceViewResolver来解析视图。之前分析过,InternalResourceViewResolver重写了UrlBasedViewResolver的buildView方法。但是还是会调用UrlBasedViewResolver的buildView方法。

image

最终得到InternalResourceView或JstlView视图。这两个视图的render方法本文介绍重要接口及类的时候已分析。

特别参考[Format大佬的分享]http://www.cnblogs.com/fangjian0423/p/springMVC-view-viewResolver.html

猜你喜欢

转载自blog.csdn.net/sinat_29039125/article/details/88043358
今日推荐