Spring MVC ViewResolver技術

在Spring MVC中,當Controller將請求處理結果放入到ModelAndView中之後,DispatcherServlet會根據 ModelAndView選擇合適的視圖進行渲染。html

  1. 如何選擇合適的View呢?
  2. View對象是是如何建立的呢?

ViewResolver接口定義了 resolverViewName方法,根據viewName建立合適類型的View實現。配置ViewResolver呢?在Spring中,ViewResolver做爲Spring Bean存在,能夠在Spring配置文件中進行配置,例以下面的代碼,配置了jsp相關的viewResolver。java

    <!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory -->  
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
            <property name="prefix" value="/WEB-INF/views/"/>  
            <property name="suffix" value=".jsp"/>  
        </bean>  

 

來讓DispacherServlet進行加載默認的viewResolver,若是沒有設置viewResolver,spring使用InternalResourceViewResolver進行解析。web

 

Spring實現ViewResolver的非抽象類且咱們常常使用的viewResolver有如下四種:spring

 

InternalResourceViewResolver 將邏輯視圖名字解析爲一個路徑
BeanNameViewResolver 將邏輯視圖名字解析爲bean的Name屬性,從而根據name屬性,找定義View的bean
ResourceBundleResolver 和BeanNameViewResolver同樣,只不過定義的view-bean都在一個properties文件中,用這個類進行加載這個properties文件
XmlViewResolver 和ResourceBundleResolver同樣,只不過定義的view-bean在一個xml文件中,用這個類來加載xml文件

 

使用多視圖解析器:能夠在[spring-dispatcher-name]-servlet.xml定義多個viewResolver:安全

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/jsp/"/> <property name="suffix" value=".jsp"/> </bean>
<bean id=」beanNameViewResolver」 class=」...BeanNameViewResolver」> <property name="order" value="1"></property> </bean>
<bean id=」beanNameViewResolver」 class=」...XmlViewResolver」> <property name="order" value="0"></property> </bean>

DispatcherServlet會加載全部的viewResolver到一個list中,並按照優先級進行解析。注意order中的值越小,優先級越高。而id爲viewResolverapp

的viewResolver的優先級是最低的。jsp

 

ViewResolver是使用bean來配置的,因此擴展起來很是的容易,能夠根據本身的須要定製ViewResolver,而後在配置文件中進行相關的配置便可。this

ViewResolver接口聲明瞭resolverViewName方法,這個方法的主要功能是根據ModelAndView中給定的viewName信息,再結合相關的配置,建立出合適類型的View對象。spa

ViewResolver接口是在DispatcherServlet中進行調用的,當DispatcherServlet調用完 Controller後,會獲得一個ModelAndView對象,而後DispatcherServlet會調用render方法進行視圖渲染。線程

    protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {  
            // Determine locale for request and apply it to the response.  
            Locale locale = this.localeResolver.resolveLocale(request);  
            response.setLocale(locale);  
      
            View view;  
            if (mv.isReference()) {  
                // We need to resolve the view name.  
                view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);  
                if (view == null) {  
                    throw new ServletException(  
                            "Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" +  
                                    getServletName() + "'");  
                }  
            }  
            else {  
                // No need to lookup: the ModelAndView object contains the actual View object.  
                view = mv.getView();  
                if (view == null) {  
                    throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +  
                            "View object in servlet with name '" + getServletName() + "'");  
                }  
            }  
      
            // Delegate to the View object for rendering.  
            if (logger.isDebugEnabled()) {  
                logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");  
            }  
            view.render(mv.getModelInternal(), request, response);  
        }  
在DispatcherServlet類中,init方法中已經進行了相關的初始化,配置的ViewResolver信息都存放在 viewResolvers中。在render方法中調用resolverViewName方法,在這個方法中逐一調用ViewResolver去取得 View對象。
    protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,  
            HttpServletRequest request) throws Exception {  
      
        for (ViewResolver viewResolver : this.viewResolvers) {  
            View view = viewResolver.resolveViewName(viewName, locale);  
            if (view != null) {  
                return view;  
            }  
        }  
        return null;  
    }  

 

        在這裏須要關於ViewResolver的選擇是經過循環進行的,只選擇第一個符合要求的,所以在定義ViewResolver時,須要注意定義其優先級。

        下面就來着重關注一下ViewResolver的類結構。

 ViewResolver類結構圖

 

       關於View對象的建立,不一樣的ViewResolver的解決方法是各部相同的。如BeanNameViewResolver是根據viewName選 擇相應名稱的bean(這裏須要注意bean的scope,是否須要線程安全),而UrlBasedViewResolver則是使用反射機制,根據 viewClass信息建立view對象,所以這個view不受IoC容器的管理。ContentNegotiationViewResolver中能夠 嵌套ViewResolver,根據不一樣的的請求類型選擇合適的ViewResolver。

       DispatcherServlet獲得View對象後,即調用View的render方法,執行真正的渲染工做。

       最後,看一下View的類結構圖。

 View類結構圖

       有上述的View類結構圖可知,Spring已經爲咱們提供了一系列可用的View。同時,若是當前提供的View不能知足咱們的要求時,能夠經過實現 View接口進行擴展。如須要根據model中的數據使用JFreeChart繪圖,或者將這些數據做爲文件下載時,咱們能夠擴展出 JFreeChartView和FileDownloadView等,這樣就能更靈活的將同一份數據用不一樣的方式展示出來。

相關文章
相關標籤/搜索