Spring MVC 混合使用多種視圖技術


1.ContentNegotiatingViewResolver

Spring 最重要的一個新功能就是對 REST 編程風格的支持。REST 風格的應用對資源的 URL 定義有嚴格的要求:一個資源對象對應唯一的 URL。在前面的例子中,我們使用不同的視圖顯示用戶列表,如果把“用戶列表”看作一個資源,那么我們希望通過一個相同的 URL 訪問這個資源,而不是使用不同的 URL 訪問該資源的不同視圖。

前面介紹了使用 HttpMessageConverter 對標注了 @ResponseBody 或返回值為 ResponseEntity 的處理器方法進行響應信息轉換的內容,Spring MVC 可以根據請求報文頭的 Accept 屬性選擇適合的 HttpMessageConverter 將處理方法的返回值以 XML、JSON 等不同形式輸出響應。也就是說,調用者可以通過設置請求報文頭的 Accept 值控制服務器端返回的數據格式,從而實現對同一資源采用相同 URL 的 REST 編程風格。

但是基於 HttpMessageConverter 的實現方式存在以下限制。

1)只能通過請求報文頭的 Accept 值控制服務器端返回的數據格式。如果客戶端是瀏覽器,那么,除非使用 AJAX,否則很難控制 Accept 報文頭的值。一般情況下,該值是由瀏覽器自己決定的。

2)無法通過 URL 擴展名或請求參數控制服務器端的資源輸出形式,因此無法將其對應一個 URL 發布出去。

3)如果希望使用 XML、JSON、一個網頁等形式輸出資源,則 HttpMessageConverter 很難達到要求。因為  HttpMessageConverter 很難調用一個視圖對象渲染模型,它直接負責將資源輸出為某一內容形式。

所以,如果希望將資源以 XML、JSON 等純數據的格式輸出,且不在意使用報文頭控制資源輸出,那么適合選擇 HttpMessageConverter 實現方式。否則,建議采用 Spring MVC 的 ContentNegotiatingViewResolver 視圖解析器,雖然它和 HttpMessageConverter 在功能上有一些重疊,但在使用上更加靈活。

ContentNegotiatmgViewResolver 名為“視圖解析器”,但它並不是一個傳統意義上的視圖解析器,它像一個仲裁機構或一個代理人,根據請求信息從上下文中選擇一個適合的視圖解析器負責解析。因此,一般將 ContentNegotiatingViewResolver 的優先級設為最高,以保證優先調用 ContentNegotiatingViewResolver。

ContentNegotiatingViewResolver 根據請求所要求的 MIME 類型決定由哪個視圖解析器負責處理,它按照如下方式工作。

1)如果其 favorPathExtension 屬性設置為 true(默認為 true),則根據 URL 中的文件擴展名確定 MIME 類型(如 userList.xml,userList.json 等)。

2)如果其 favorParameter 屬性設置為 true(默認為 false),則根據請求參數的值確定 MIME 類型。默認的請求參數是 format,可以通過 parameterName 屬性指定一個自定義的參數。

3)如果還沒有找到對應的 MIME 類型,且 Java Activation Framework(JAF)位於類路徑下,則通過 JAF 的  FileTypeMap.geContentType(url) 方法對 URL 進行判斷,以獲取對應的 MIME 類型。

4)如果以上步驟都失敗,且 ignoreAcceptHeader 屬性設置為 false(默認為 false),則采用 Accept 請求報文頭的值確定 MIME 類型。由於不同瀏覽器產生的 Accept 頭都是不一樣的,所以一般不建議采用 Accept 確定 MIME 類型。

 

2.使用同一 URL 獲取不同形式的返回內容

假設希望使用以下 REST 風格的 URL 以不同的 MIME 格式獲取相同的資源(用戶列表)。

1)/user/showUserListMix.html:返回一個 HTML 頁面顯示的用戶列表。

2)/user/showUserListMix.html?content=xml:返回 XML 格式的用戶列表。

3)/user/showUserListMix.html?content=json:返回 JSON 格式的用戶列表。

首先,在 UserController 中添加一個處理方法。

@RequestMapping(value = "/showUserListMix")
public String showUserListMix(ModelMap mm) {
    List<User> userList = new ArrayList<User>();
    //...
    mm.addAttribute("userList", userList);
    return "userListMix";
}

接着,在 smart-servlet.xml 中添加以下配置片段,配置一個 ContentNegotiafingVrewResolver。采用請求參數指定內容資源的返回類型,如下面代碼所示。

<bean id="contentNegotiationManager"
    class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"
    p:ignoreAcceptHeader="true"
    p:favorPathExtension="false"
    p:favorParameter="true"
    p:parameterName="format"
    p:defaultContentType="text/html"><!-- ① 不支持擴展文件名,不支持Accept報文頭,指定MIME類型 -->
    <property name="mediaTypes"><!-- 通過請求指定MIME類型,參數名為content,請求類型的參數值和MIME類型的映射列表-->
        <value>
            html=text/html
            xml=application/xml
            json=application/json
        </value>
    </property>
</bean>
<!-- 協商多種視圖解析器 -->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver" 
    p:order="0"><!-- ② -->
    <property name="contentNegotiationManager" ref="contentNegotiationManager"/>
    <property name="defaultViews">
        <list>
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"
                  p:modelKeys="userList"/><!-- ③ -->
            <bean class="org.springframework.web.servlet.view.xml.MarshallingView"
                  p:modelKey="userList" p:marshaller-ref="xmlMarshaller"/><!-- ④ -->
        </list>
    </property>
</bean>

<!-- 以下是上下文中已經配置的視圖解析器 -->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"
    p:order="10"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"<!-- ⑤ -->
    p:order="100" p:viewClass="org.springframework.web.servlet.view.JstlView"
    p:prefix="/WEB-INF/views/" p:suffix=".jsp"/>

ContentNegotiatingViewResolver 會在上下文中查找和 MIME 類型匹配的視圖解析器,並委托它們進行視圖解析。這樣通過 content 請求參數就可以控制資源的輸出格式。

③處配置的是 JSON 視圖對象,而④處配置的是 XML 視圖對象,它們都是默認的候選視圖對象,會覆蓋對應視圖解析器返回的視圖對象。換句話說,當資源 URL 帶 content=json 參數時,直接返回③處對應的視圖對象:當資源 URL 帶 content=xml 參數時,直接返回④處對應的視圖對象;當資源 URL 帶 content=html 參數時,由⑤處的

InternalResourceViewResolver 解析;當資源 URL 不帶 content 參數時,由於已經通過 defaultContentType="text/html',指定了默認的 MIME 類型,因此也由⑤處的 InternalResourceViewResolver 解析。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM