1、簡介
不少朋友可能疑惑過,在SpringMVC中爲何一樣是返回一個字符串,有的前端獲得的是頁面,有的獲得是json數據。 由於使用了不一樣的Handler,有@ResponseBody註解的使用了RequestResponseBodyMethodProcessor,後一個方法使用了ViewNameMethodReturnValueHandler。前端
固然,它們都是HandlerMethodReturnValueHandler,SpringMVC到底怎麼玩的呢?web
咱們來看一個簡化版本的流程圖,能夠幫助咱們快速理清楚脈絡,避免被龐雜的代碼繞暈。spring
知道了MVC的大體流程,咱們就來重點關注一下ViewResolver部分json
2、ViewResolver
ViewResolver用於解決從邏輯視圖到View,通常邏輯視圖就是viewName,就是根據返回的字符串找到對應的View。緩存
2.1 AbstractCachingViewResolver
AbstractCachingViewResolver一看就知道是一個抽象類,專門爲繼承設計的。jsp
它作的最重要的工做就是緩存,就是把已經解析過的視圖保存起來,這樣能夠避免每一次解析。url
2.2 UrlBasedViewResolver
UrlBasedViewResolver繼承了AbstractCachingViewResolver,主要就是提供的一種拼接URL的方式來解析視圖。spa
能夠prefix、suffix來簡化視圖名稱,默認的prefix和suffix都是空。設計
URLBasedViewResolver支持"redirect:"前綴,經過轉換爲RedirectView實現,這樣就能夠支持URL在客戶端的跳轉code
URLBasedViewResolver支持"forword:"前綴,經過InternalResourceView實現。
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"> <property name="prefix" value="/WEB-INF/" /> <property name="suffix" value=".jsp" /> <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/> </bean>
2.3 InternalResourceViewResolver
InternalResourceViewResolver繼承了URLBasedViewResolver,因此URLBasedViewResolver支持的特性它都支持。
InternalResourceViewResolver和URLBasedViewResolver差很少,InternalResourceViewResolver主要就是獲取InternalResourceView,就是爲了處理JSP和JSTL的。
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/"/> <property name="suffix" value=".jsp"></property> </bean>
2.4 XmlViewResolver
XmlViewResolver直接繼承AbstractCachingViewResolver抽象類,因此它也是支持視圖緩存的。
xml不是解析xml的,而是用一個xml文件來配置,視圖名稱和View之間的對應關係,經過location屬性指定配置文件,默認/WEB-INF/views.xml。
<bean class="org.springframework.web.servlet.view.XmlViewResolver"> <property name="location" value="/WEB-INF/views.xml"/> <property name="order" value="1"/> </bean>
2.5 BeanNameViewResolver
BeanNameViewResolver和XmlViewResolver很像,就是經過視圖名稱(Controller中方法返回的字符串)去找作爲id去找View。
與XmlViewResolver不一樣的是,BeanNameViewResolver的View不用單獨寫xml文件了。
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"> <property name="order" value="1"/> </bean> <bean id="index" class="org.springframework.web.servlet.view.InternalResourceView"> <property name="url" value="/index.jsp"/> </bean>
2.6 ResourceBundleViewResolver
ResourceBundleViewResolver就是XmlViewResolver的properties版本。
例如,下面的properties,等價於後面的xml配置
test1.(class)=org.springframework.web.servlet.view.InternalResourceView test1.url=/test1.jsp test2.(class)=org.springframework.web.servlet.view.InternalResourceView test2.url=/test2.jsp
等價於:
<bean id="test1" class="org.springframework.web.servlet.view.InternalResourceView"> <property name="url" value="/test1.jsp"/> </bean> <bean id="test2" class="org.springframework.web.servlet.view.InternalResourceView"> <property name="url" value="/test2.jsp"/> </bean>
ResourceBundleViewResolver的配置文件是一個屬性文件,並且必須是放在classpath路徑下面的,默認狀況下這個配置文件是在classpath根目錄下的views.properties文件。
能夠經過屬性baseName或baseNames來指定屬性文件名稱,Spring會在指定的classpath根目錄下尋找以指定的baseName開始的屬性文件進行View解析。
例如,baseName爲base,那麼base.properties、baseABC.properties、base123.properties等以base開始的屬性文件都會被Spring當作ResourceBundleViewResolver解析視圖的資源文件。
3、多個ViewResolver處理流程
在SpringMVC中通常會存在多個ViewResolver
上面是DispatcherServlet初始化ViewResolver。
在SpringMVC中能夠同時定義多個ViewResolver視圖解析器,而後它們會組成一個ViewResolver鏈。
多個ViewResolver將根據ViewResolver的優先級來進行處理。
在ViewResolver中是經過order屬性來指定順序的,默認都是最大值。order越小,對應的ViewResolver優先級越高,因此第一個進行解析的將是ViewResolver鏈中order值最小的那個。
當一個ViewResolver在進行視圖解析後返回的View對象是null則表示該ViewResolver不能解析該視圖。
這個時候若是還存在其餘order值比它大的ViewResolver,就會調用剩餘的ViewResolver中的order值最小的那個來解析該視圖,依次調用。
當ViewResolver在進行視圖解析後返回的是一個非空的View對象的時候,視圖解析結束,若是沒有解析到有View,返回null。
這一部分邏輯在DispatcherServlet的resolveViewName方法中: View部分是比較複雜的,可是通常也不多關注的,由於View部分更加在於的是細節,咱們看一下View的繼承結構圖。