(Notice:以下所有经验也是我根据网上的经验整理的,如有侵权可以联系我删除,欢迎交流和沟通,Wx:IT_Ezra,QQ 654303408。 有问题讨论也可联系我。)
(PS:SpringMVC是目前主流的Web MVC框架之一,其工作流程我在之前的文章中介绍了,下面我想重点讲一下SprignMVC的识图解析器。)
image.png
(PS:我认为最最最核心的流程:下马威)
首先,我们可以根据这个图把整个流程走一遍。首先来了一个请求,然后通过DispatcherServlet,DispatcherServlet的init加载的mapperHandler类的getHandler()方法得到handler,DispatcherServlet的init加载的RequestMappingHandlerAdapter类的handle()方法返回ModelAndView, 然后把ModelAndView传到视图解析器(InternalResourceViewResolver)解析,InternalResourceViewResolver继承了UrlBasedViewResolver类,UrlBasedViewResolver类继承AbstractCachingViewResolver抽象类,AbstractCachingViewResolver抽象类会首先createView()方法,其内部调用loadView()方法,loadView()方法里面调用了buildView()方法,然后返回一个InternalResourceView视图。
------------------------------------------------------------------------------------------------------
然后开始介绍重要的借口和类。
视图基础接口,它的各种实现是么有状态的,所以也是线程安全的。该接口定义了两个方法。
View接口
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>
JSTL视图,继承自InternalResourceView,该类大致上与InternalResourceView类一致。
-
6. AbstractTemplateView抽象类
继承自AbstractUrlBasedView抽象类,重写了renderMergedOutputModel方法,在该方法中会调用renderMergedTemplateModel方法,renderMergedTemplateModel方法为新定义的抽象方法。
该抽象类有几个boolean属性exposeSessionAttributes,exposeRequestAttributes。 设置为true的话会将request和session中的键值和值丢入到renderMergedTemplateModel方法中的model这个Map参数中。
这个类是某些模板引擎视图类的父类。 比如FreemarkerView,VelocityView。
视图解释器,用来解析视图View,与View接口配合使用。
该接口只有1个方法,通过视图名称viewName和Locale对象得到View接口实现类:
-
8. AbstractCachingViewResolver抽象类
带有缓存功能的ViewResolver接口基础实现抽象类,该类有个属性名为viewAccessCache的以 "viewName_locale" 为key, View接口为value的Map。
该抽象类实现的resolveViewName方法内部会调用createView方法,方法内部会调用loadView抽象方法。
继承自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视图设置属性
顾名思义,带有视图和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方法本文介绍重要接口及类的时候已分析。
网友评论