1. 程式人生 > >SpringMVC工作原理之三:ViewResolver

SpringMVC工作原理之三:ViewResolver

一、ViewResolver

根據檢視的名稱將其解析為 View 型別的檢視,如通過 ModelAndView 中的檢視名稱將其解析成 View,View 是用來渲染頁面的,也就是將 Model 填入模板中,生成 html 或其他格式的檔案。

可以設定多個解析策略,如可以根據 JSP 來解析,或者按照 Velocity 模版解析,如果設定了多個解析策略則可以通過 order 屬性來設定其優先順序,數值越小優先順序越高,前面的檢視解析器解析後就不會讓後面的繼續解析。預設的解析策略是 InternalResourceViewResolver,按照 JSP 頁面來解析。ViewResolver 介面中的方法如下:

  • View resolveViewName(String viewName, Locale locale);

1 帶有快取的 ViewResolver

AbstractCachingViewResolver 是帶有快取的 ViewResolver,它每次解析時先從快取裡查詢,如果找到檢視就返回,沒有就建立新的檢視,且建立新檢視的方法由其子類實現,具體程式碼如下所示:

複製程式碼
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
    // 是否啟用快取,可通過setCache()方法或setCacheLimit()方法開啟快取,是一個ConcurrentHashMap,預設快取大小1024
if (!isCache()) { return createView(viewName, locale); } else { // 得到 view 在快取中的 key 值 Object cacheKey = getCacheKey(viewName, locale); View view = this.viewAccessCache.get(cacheKey); // 如果沒有找到 view 則建立,採用雙重校驗的方式進行安全建立 if (view == null) {
synchronized (this.viewCreationCache) { view = this.viewCreationCache.get(cacheKey); if (view == null) { // 具體的建立方式由子類實現 view = createView(viewName, locale); if (view == null && this.cacheUnresolved) { view = UNRESOLVED_VIEW; } if (view != null) { this.viewAccessCache.put(cacheKey, view); this.viewCreationCache.put(cacheKey, view); } } } } return (view != UNRESOLVED_VIEW ? view : null); } }
複製程式碼

1.1 ResourceBundleViewResolver

ResourceBundleViewResolver 根據 views.properties 檔案來解析檢視,這個檔案位於 classpath 路徑下,使用方式如下:

<bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver">  
    <!-- 設定屬性檔名為views -->  
    <property name="basename" value="views"></property>  
</bean>  

1.2 XmlViewResolver

XmlViewResolver 根據 xml 檔案來解析檢視,使用方式如下:

<bean class="org.springframework.web.servlet.view.XmlViewResolver">
    <property name="location">
        <value>/WEB-INF/spring-views.xml</value>
    </property>
</bean>

1.3 UrlBasedViewResolver

UrlBasedViewResolver 提供了拼接 URL 的方式來解析檢視,通過 prefix 屬性拼接一個字首,通過 suffix 屬性拼接一個字尾,就得到了檢視的 URL。還可以加入 redirect: 與 forword: 字首,使用 redirect: 字首會呼叫 HttpServletResponse物件的 sendRedirect() 方法進行重定向,使用 forword: 字首會利用 RequestDispatcher的forword 方式跳轉到指定的地址。另外,使用時還要指定 viewClass 屬性,表示要解析成哪種 View,的使用方式如下:

<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>  

1.4 InternalResourceViewResolver 

InternalResourceViewResolver 是 UrlBasedViewResolver 的子類,將 InternalResourceView 作為預設的 View 類,但如果當前classpath 中有 jstl 的 jar 包時則使用 JstlView 作為 view 來渲染。

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
       <property name="prefix" value="/WEB-INF/jsp/" />
       <property name="suffix" value=".jsp" />
</bean>

2 其他的 ViewResolver

2.1 BeanNameViewResolver

BeanNameViewResolver 是通過檢視名稱去容器中獲取對應的 view 對像,所以在使用前需要將 view 物件註冊到容器中。它沒有快取,實現方式如下:

複製程式碼
@Override
public View resolveViewName(String viewName, Locale locale) throws BeansException {
    ApplicationContext context = getApplicationContext();
    if (!context.containsBean(viewName)) {
        // Allow for ViewResolver chaining...
        return null;
    }
    if (!context.isTypeMatch(viewName, View.class)) {
        // Since we're looking into the general ApplicationContext here,
        // let's accept this as a non-match and allow for chaining as well...
        return null;
    }
    return context.getBean(viewName, View.class);
}
複製程式碼