(Notice:以下所有經驗也是我根據(jù)網上的經驗整理的,如有侵權可以聯(lián)系我刪除,歡迎交流和溝通,Wx:IT_Ezra,QQ 654303408。 有問題討論也可聯(lián)系我。)
(PS:SpringMVC是目前主流的Web MVC框架之一,其工作流程我在之前的文章中介紹了,下面我想重點講一下SprignMVC的識圖解析器。)

image.png
(PS:我認為最最最核心的流程:下馬威)
首先,我們可以根據(jù)這個圖把整個流程走一遍。首先來了一個請求,然后通過DispatcherServlet,DispatcherServlet的init加載的mapperHandler類的getHandler()方法得到handler,DispatcherServlet的init加載的RequestMappingHandlerAdapter類的handle()方法返回ModelAndView, 然后把ModelAndView傳到視圖解析器(InternalResourceViewResolver)解析,InternalResourceViewResolver繼承了UrlBasedViewResolver類,UrlBasedViewResolver類繼承AbstractCachingViewResolver抽象類,AbstractCachingViewResolver抽象類會首先createView()方法,其內部調用loadView()方法,loadView()方法里面調用了buildView()方法,然后返回一個InternalResourceView視圖。
------------------------------------------------------------------------------------------------------
然后開始介紹重要的借口和類。
-
1.View接口
視圖基礎接口,它的各種實現(xiàn)是么有狀態(tài)的,所以也是線程安全的。該接口定義了兩個方法。
View接口

View接口
-
2. AbstractView抽象類
View接口的基礎實現(xiàn)類。我們稍微介紹一下這個抽象類。
AbstractView抽象類

AbstractView抽象類
其中非常重要的一個方法render方法,該方法里面有一個抽象方法renderMergedOutputModel方法(AbstractView抽象類定義的抽象方法,為View接口提供的render方法服務)。

render方法
-
3. AbstractUrlBasedView抽象類
繼承自AbstractView抽象類,增加了1個類型為String的url參數(shù)。
-
4. InternalResourceView類(重點類,我們在配置Springmvc的時候經常會看到它的配置)
繼承自AbstractUrlBasedView抽象類的類,表示JSP視圖。
我們看下這個類的renderMergedOutputModel方法(AbstractView抽象類定義的抽象方法,為View接口提供的render方法服務)。這個抽象類里面可一看到最后決定用include方法還是forward方法。這兩個方法都是重定向方法,但是區(qū)別不同的是,惟一的不同在于:利用include()方法將HTTP請求轉送給其他Servlet后,被調用的Servlet雖然可以處理這個HTTP請求,但是最后的主導權仍然是在原來的Servlet。RequestDispatcher是一個Web資源的包裝器,可以用來把當前request傳遞到該資源,或者把新的資源包括到當前響應中。

renderMergedOutputModel
我們在SpringMVC的配置文件里面,會配置視圖解析器,目前主流的就是InternalResourceView類,當然它的實現(xiàn)也是依賴于另一個抽象類AbstractCachingViewResolver(后文會講到)。我們繼續(xù)介紹其他類和接口
<!-- 視圖解析器 -->
<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參數(shù)中。
這個類是某些模板引擎視圖類的父類。 比如FreemarkerView,VelocityView。
-
7. ViewResolver接口
視圖解釋器,用來解析視圖View,與View接口配合使用。
該接口只有1個方法,通過視圖名稱viewName和Locale對象得到View接口實現(xiàn)類:
-
8. AbstractCachingViewResolver抽象類
帶有緩存功能的ViewResolver接口基礎實現(xiàn)抽象類,該類有個屬性名為viewAccessCache的以 "viewName_locale" 為key, View接口為value的Map。
該抽象類實現(xiàn)的resolveViewName方法內部會調用createView方法,方法內部會調用loadView抽象方法。
-
9. UrlBasedViewResolver類
繼承自AbstractCachingViewResolver抽象類、并實現(xiàn)Ordered接口的類,是ViewResolver接口簡單的實現(xiàn)類

AbstractCachingViewResolver
該類復寫了createView方法:
createView

createView
父類(AbstractCachingViewResolver)的createView方法內部會調用loadView抽象方法,UrlBasedViewResolver實現(xiàn)了這個抽象方法:

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參數(shù)都會被丟入到staticAttributes屬性中,這個staticAttributes會被設置成AbstractView的staticAttributes屬性,也就是request域中的參數(shù)。

image

image

image
我們看到request域中沒有設置mytest和testvalue值。但是頁面中會顯示,因為我們配置了attributesMap和attributes參數(shù)。
如果我們把viewNames中的"*"改成"index1"。那么就報錯了,因為處理視圖名的時候index匹配不上index1。

image
-
10. InternalResourceViewResolver類
繼承自UrlBasedViewResolver,以InternalResourceView作為視圖,若項目中存在“javax.servlet.jsp.jstl.core.Config”該類,那么會以JstlView作為視圖。重寫了buildView方法,主要就是為了給InternalResourceView視圖設置屬性
-
11. ModelAndView對象
顧名思義,帶有視圖和Model屬性的一個模型和視圖類。

image
值得注意的是,這個視圖屬性是一個Object類型的數(shù)據(jù),可以直接是View接口的實現(xiàn)類或者視圖名(字符串)。
-------------------------------------------------------------------------------------------------------------------------------------------
下面我們來分析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