springMVC4(15)RestFul多視圖混合輸出


4# 混合使用多種視圖技術。
在前面文章里,我們對jsp、json、xml個中視圖都進行了較為詳細的實例解析,但涉及到的都是單視圖使用配置。在實際開發中,我們可能需要混合是使用多種視圖技術。尤其是針對REST編程風格,我們可以通過一個URL、多種視圖來切合REST風格的同一資源、多種表述
現在加入我們要輸出JSP、JSON、XML多種視圖技術,如果使用我之前文章《springMVC4(4)json與對象互轉實例解析請求響應數據轉換器 》提到的HttpMessageConvert來完成數據類型輸出切換。它相對於多視圖輸出的局限性是:
1. 必須通過HTTP請求頭的Accept來控制轉換器的使用類型,如果客戶端是安卓等還能通過HttpClient、RestTemplate等控制,但如果客戶端是游覽器,除非使用AJAX技術,否則很難控制請求頭內容
2. 無法通過URL擴展名或請求參數來控制服務端的資源輸出類型。而使用多種視圖技術,我們可以通過以下形式控制輸出不同視圖:
1. 擴展名:
1. /user.xml 呈現xml文件
2. /user.json 呈現json格式
3. /user.xls 呈現excel文件
4. /user.pdf 呈現pdf文件
5. /user 使用默認view呈現,比如jsp等
2. 請求參數:
1. /user?type=xml 呈現xml文件
2. /user?type=json 呈現json格式
3. /user?type=xls 呈現excel文件
4. /user?type=pdf 呈現pdf文件
5. /user? 使用默認view呈現,比如jsp等

ContentNegotiatingViewResolver

我們使用ContentNegotiatingViewResolver視圖解析器來完成多種視圖混合解析,從它的名字上看,它是一個視圖協調器,負責根據請求信息從當前環境選擇一個最合適的解析器進行解析,也即是說,它本身並不負責解析視圖。
它有3個關鍵屬性:
1. favorPathExtension:如果設置為true(默認為true),則根據URL中的文件拓展名來確定MIME類型
2. favorPathExtension:如果設置為true(默認為false),可以指定一個請求參數確定MIME類型,默認的請求參數為format,可以通過parameterName屬性指定一個自定義屬性。
3. ignoreAcceptHeader(默認為false),則采用Accept請求報文頭的值確定MIME類型。由於不同游覽器產生的Accept頭不一致,不建議采用Accept確定MIME類型。
在實際流程中,ContentNegotiatingViewResolver也是根據以上三個互斥屬性的配置情況來確定視圖類型,其中屬性1優先級最高,屬性3優先級最低

除了以上三個屬性,還有一個關鍵屬性是mediaTypes,用來配置不同拓展名或參數值映射到不同的MIME類型
在前面,我們展示了使用jsp/模板、json、xml、Excel等來呈現我們的視圖,下面我們通過整合上述視圖來分析我們的多視圖混合技術

多視圖混合Rest呈現實例

1. 配置視圖解析器

<!-- 根據確定出的不同MIME名,使用不同視圖解析器解析視圖 -->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<!-- 設置優先級 -->
<property name="order" value="1" />
<!-- 設置默認的MIME類型,如果沒有指定拓展名或請求參數,則使用此默認MIME類型解析視圖 -->
<property name="defaultContentType" value="text/html" />
<!-- 是否不適用請求頭確定MIME類型 -->
<property name="ignoreAcceptHeader" value="true" />
<!-- 是否根據路徑拓展名確定MIME類型 -->
<property name="favorPathExtension" value="false" />
<!-- 是否使用參數來確定MIME類型 -->
<property name="favorParameter" value="true" />
<!-- 上一個屬性配置為true,我們指定type請求參數判斷MIME類型 -->
<property name="parameterName" value="type" />
<!-- 根據請求參數或拓展名映射到相應的MIME類型 -->
<property name="mediaTypes">
<map>
<entry key="html" value="text/html" />
<entry key="xml" value="application/xml" />
<entry key="json" value="application/json" />
<entry key="excel" value="application/vnd.ms-excel"></entry>
</map>
</property>
<!-- 設置默認的候選視圖,如果有合適的MIME類型,將優先從以下選擇視圖,找不到再在整個Spring容器里尋找已注冊的合適視圖 -->
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.InternalResourceView">
<property name="url" value="WEB-INF/views/hello.jsp"></property>
</bean>
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />

<ref local="myXmlView" />
<bean class="com.mvc.view.ExcelView" />

</list>
</property>
</bean>
<!-- Excel視圖 -->
<bean class="com.mvc.view.ExcelView" id="excelView" /><!-- 注冊自定義視圖 -->
<bean class="org.springframework.web.servlet.view.xml.MarshallingView"
id="myXmlView">

<property name="modelKey" value="articles" />
<property name="marshaller" ref="xmlMarshaller" />
</bean>
<bean class="org.springframework.oxm.xstream.XStreamMarshaller"
id="xmlMarshaller">
<!-- 將模型數據轉換為XML格式 -->
<property name="streamDriver">
<bean class="com.thoughtworks.xstream.io.xml.StaxDriver" />
</property>
</bean>

關於以上視圖文件的配置實體講解可移步參考我前面的文章

2. jsp視圖文件

<%@page import="com.mvc.model.Article"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>hello spring mvc</title>
</head>
<body>
<c:out value="${articles}"></c:out>
</body>
</html>

3. Excel配置文件

package com.mvc.view;

import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.springframework.web.servlet.view.document.AbstractExcelView;

import com.mvc.model.Article;

public class ExcelView extends AbstractExcelView {

@Override
protected void buildExcelDocument(Map<String, Object> model,
HSSFWorkbook workbook, HttpServletRequest request,
HttpServletResponse response) throws Exception {
List<Article> articles= (List<Article>) model.get("articles");

HSSFSheet sheet = workbook.createSheet("文章列表");//創建一頁
HSSFRow header = sheet.createRow(0);//創建第一行
header.createCell(0).setCellValue("標題");
header.createCell(1).setCellValue("正文");
for( int i = 0; i < articles.size();i++){
HSSFRow row = sheet.createRow(i + 1);
Article article = articles.get(i);
row.createCell(0).setCellValue(article.getTitle());
row.createCell(1).setCellValue(article.getContent());
}
}

}

4. Article POJO類

package com.mvc.model;

public class Article {
private String title;
private String content;

//忽略get和set方法
@Override
public String toString() {
return "Article [ title=" + title + ", content="
+ content + "]";
}

}

5. 控制器測試方法

@RequestMapping("views")
public String views(ModelMap map,HttpServletRequest request){
List<Article>articles = new ArrayList<Article>();
for(int i = 0 ; i < 5; i ++){
Article article = new Article();
article.setTitle("title" +i);
article.setContent("content" + i);
articles.add(article);
}
map.addAttribute("articles",articles);//將文章對象綁定到
return "views";
}

6. 進行測試

我們使用了參數type來映射不同的視圖類型:

1. 默認參數類型:

這里寫圖片描述

2. html參數類型

這里寫圖片描述

3. json參數類型

這里寫圖片描述

4. xml參數類型

這里寫圖片描述

5. excel參數類型

這里寫圖片描述
點擊下載后打開如下圖所示:
這里寫圖片描述

7. 使用拓展名類型

上面我們使用參數的方法訪問,如果我們改成使用拓展名的形式,如下所示,只需去掉其中的4行配置:

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"><!-- 根據確定出的不同MIME名,使用不同視圖解析器解析視圖 -->
<property name="order" value="1" /><!-- 設置優先級 -->
<property name="defaultContentType" value="text/html" /><!-- 設置默認的MIME類型,如果沒有指定拓展名或請求參數,則使用此默認MIME類型解析視圖 -->
<property name="mediaTypes"><!-- 根據請求參數映射到相應的MIME類型 -->
<map>
<entry key="html" value="text/html" />
<entry key="xml" value="application/xml" />
<entry key="json" value="application/json" />
<entry key="excel" value="application/vnd.ms-excel"></entry>
</map>
</property>
<property name="defaultViews"><!-- 設置默認的候選視圖,如果有合適的MIME類型,將優先從以下選擇視圖,找不到再在整個Spring容器里尋找已注冊的合適視圖 -->
<list>
<bean class="org.springframework.web.servlet.view.InternalResourceView">
<property name="url" value="WEB-INF/views/hello.jsp"></property>
</bean>
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />

<ref local="myXmlView" />
<bean class="com.mvc.view.ExcelView" />
</list>
</property>
</bean>

這個時候,我們就可以使用:
http://localhost:8080/springMVC/views
http://localhost:8080/springMVC/views.html,
http://localhost:8080/springMVC/views.json
http://localhost:8080/springMVC/views.xml
來對應得到與上面相同的內容。感興趣的朋友可在下面下載源碼自行測試

源碼下載

本節內容源碼可到http://github.com/jeanhao/spring的multiViews文件夾下下載


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com