Spring4 MVC ContentNegotiatingViewResolver多種輸出格式實例
本文演示支持多種輸出格式,這裏 Spring4 MVC應用程序使用了 Spring ContentNegotiatingViewResolver 。我們將生成應用程序輸出XML,JSON,PDF,XLS和HTML格式,全部採用基於註解配置的。
ContentNegotiatingViewResolver是 ViewResolver 使用所請求的媒體類型的一個實現(基於文件類型擴展,輸出格式URL參數指定類型或接受報頭)來選擇一個合適的視圖一個請求。ContentNegotiatingViewResolver本身並不解決視圖,只不表示爲其他的 ViewResolver,您可以配置來處理特定的視圖(XML,JSON,PDF,XLS,HTML,..)。
這裏需要使用到以下技術:
- Spring 4.0.6.RELEASE
- jackson-databind 2.4.1.3
- jackson-annotations 2.4.1
- lowagie itext 4.2.1
- Apache POI 3.10-beta2
- Maven 3
- JDK 1.6
- Tomcat 7.0.54
- Eclipse JUNO Service Release 2
我們現在就開始!
第1步:創建目錄結構
以下將是本實例的最終目錄結構:
我們將使用Spring Java配置(註釋)。現在,讓我們來添加/更新上述項目結構中提到的內容。
第2步:用所需的依賴更新 pom.xml
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yiibai.springmvc</groupId>
<artifactId>ContentNegotiatingViewResolver</artifactId> <packaging>war</packaging>
<version>1.0.0</version>
<name>Spring4MVCContentNegotiatingViewResolverExample</name>
<properties>
<springframework.version>4.0.6.RELEASE</springframework.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springframework.version}</version>
</dependency>
<!-- Needed for XML View (with JAXB2) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${springframework.version}</version>
</dependency>
<!-- Needed for JSON View -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.1.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.4.1</version>
</dependency>
<!-- Needed for PDF View -->
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>4.2.1</version>
</dependency>
<!-- Needed for XLS View -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.10-beta2</version>
</dependency>
<!-- Servlet dependencies -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<warSourceDirectory>src/main/webapp</warSourceDirectory>
<warName>ContentNegotiatingViewResolver</warName> <failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<finalName>ContentNegotiatingViewResolver</finalName> </build>
</project>
上面解析 PDF 的依賴庫有點問題,可修改爲以下測試構建就沒有問題:
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.7</version>
<scope>compile</scope>
</dependency>
spring-oxm是爲了支持XML輸出生成(使用JAXB2)。 jackson-databind &jackson-annotations 提供JSON輸出支持。iText的提供PDF生成庫,支持PDF輸出。 Apache POI將有助於產生XLS輸出格式。
第3步:創建Spring配置文件類
com.yiibai.springmvc.configuration.AppConfig
package com.yiibai.springmvc.configuration;
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
import com.yiibai.springmvc.model.Pizza;
import com.yiibai.springmvc.viewresolver.ExcelViewResolver;
import com.yiibai.springmvc.viewresolver.JsonViewResolver;
import com.yiibai.springmvc.viewresolver.Jaxb2MarshallingXmlViewResolver;
import com.yiibai.springmvc.viewresolver.PdfViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.yiibai.springmvc")
public class AppConfig extends WebMvcConfigurerAdapter {
/\*
\* Configure ContentNegotiationManager
\*/
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.ignoreAcceptHeader(true).defaultContentType(
MediaType.TEXT\_HTML);
}
/\*
\* Configure ContentNegotiatingViewResolver
\*/
@Bean
public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(manager);
// Define all possible view resolvers
List<ViewResolver> resolvers = new ArrayList<ViewResolver>();
resolvers.add(jaxb2MarshallingXmlViewResolver());
resolvers.add(jsonViewResolver());
resolvers.add(jspViewResolver());
resolvers.add(pdfViewResolver());
resolvers.add(excelViewResolver());
resolver.setViewResolvers(resolvers);
return resolver;
}
/\*
\* Configure View resolver to provide XML output Uses JAXB2 marshaller to
\* marshall/unmarshall POJO's (with JAXB annotations) to XML
\*/
@Bean
public ViewResolver jaxb2MarshallingXmlViewResolver() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(Pizza.class);
return new Jaxb2MarshallingXmlViewResolver(marshaller);
}
/\*
\* Configure View resolver to provide JSON output using JACKSON library to
\* convert object in JSON format.
\*/
@Bean
public ViewResolver jsonViewResolver() {
return new JsonViewResolver();
}
/\*
\* Configure View resolver to provide PDF output using lowagie pdf library to
\* generate PDF output for an object content
\*/
@Bean
public ViewResolver pdfViewResolver() {
return new PdfViewResolver();
}
/\*
\* Configure View resolver to provide XLS output using Apache POI library to
\* generate XLS output for an object content
\*/
@Bean
public ViewResolver excelViewResolver() {
return new ExcelViewResolver();
}
/\*
\* Configure View resolver to provide HTML output This is the default format
\* in absence of any type suffix.
\*/
@Bean
public ViewResolver jspViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
讓我們來討論說明上面的類的詳細信息:
第一步是建立它用於通過委託給ContentNegotiationManager,以確定所請求的媒體類型的請求是 ContentNegotiationStrategy 列表的一個實例。默認情況下PathExtensionContentNegotiationStrategy被查詢(使用URL擴展名,例如. .xls, .pdf,.json.),接着ParameterContentNegotiationStrategy(使用請求參數 ‘format=xls’,例如),其次是HeaderContentNegotiationStrategy(使用HTTP接受頭)。
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.ignoreAcceptHeader(true).defaultContentType(
MediaType.TEXT\_HTML);
}
在我們的例子中,我們將使用URL擴展名來幫助確定媒體類型。此外,我們還設置默認介質類型TEXT_HTML在沒有文件擴展名或當文件類型是未知時,這意味着JSP視圖解析器將被用於在沒有[known] URL擴展中。
下面是 pizza.jsp 默認使用JSP視圖解析器內容
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Pizza JSP View</title>
</head>
<body>
<table border="1">
<tr>
<td>NAME</td>
<td>Flavor</td>
<td>Toppings</td>
</tr>
<tr>
<td>${pizza.name}</td>
<td>${pizza.flavor}</td>
<td>
<c:forEach var="item" items="${pizza.toppings}">
<c:out value="${item}"/>
</c:forEach>
</td>
</tr>
</table>
</body>
</html>
下一步是配置 ContentNegotaionViewResolver 本身,
public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(manager);
// Define all possible view resolvers
List<ViewResolver> resolvers = new ArrayList<ViewResolver>();
resolvers.add(jaxb2MarshallingXmlViewResolver());
resolvers.add(jsonViewResolver());
resolvers.add(jspViewResolver());
resolvers.add(pdfViewResolver());
resolvers.add(excelViewResolver());
resolver.setViewResolvers(resolvers);
return resolver;
}
我們需要設置 ContentNegotiationManager由Spring 注入,和爲每一個應用程序可能會產生輸出格式設置不同的解析器,。
最後,我們已經創建了不同的視圖解析器以對 XML,JSON,PDF,XLS 和 HTML 輸出,我們將在節中討論。
第4步:創建不同的視圖解析器
現在,讓我們創建塔實際視圖解析器
XML View Resolver:
這個視圖解析器依賴於JAXB2編組/解組產生XML輸出。domain類需要和JAXB2註釋進行註釋。
com.yiibai.springmvc.viewresolver.Jaxb2MarshallingXmlViewResolver
package com.yiiibai.springmvc.viewresolver;
import java.util.Locale;
import org.springframework.oxm.Marshaller;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.xml.MarshallingView;
public class Jaxb2MarshallingXmlViewResolver implements ViewResolver {
private Marshaller marshaller;
public Jaxb2MarshallingXmlViewResolver(Marshaller marshaller) {
this.marshaller = marshaller;
}
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
MarshallingView view = new MarshallingView();
view.setMarshaller(marshaller);
return view;
}
}
下面是域對象(標註了標準的XML註釋)在我們的例子:
com.yiibai.springmvc.model.Pizza
package com.yiibai.springmvc.model;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "pizza")
public class Pizza {
private String name;
private String flavor;
private List<String> toppings = new ArrayList<String>();
public Pizza(){
}
public Pizza(String name){
this.name = name;
this.flavor = "spicy";
this.toppings.add("Cheese");
this.toppings.add("bakon");
}
@XmlElement
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@XmlElement
public void setFlavor(String flavor) {
this.flavor = flavor;
}
public String getFlavor() {
return flavor;
}
public List<String> getToppings() {
return toppings;
}
@XmlElement
public void setToppings(List<String> toppings) {
this.toppings = toppings;
}
}
JSON View Resolver:
這個視圖解析器是使用 Spring MappingJackson2JsonView 爲了將 POJO 對象轉換成 JSON 視圖。
com.yiibai.springmvc.viewresolver.JsonViewResolver
package com.yiibai.springmvc.viewresolver;
import java.util.Locale;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
public class JsonViewResolver implements ViewResolver{
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
MappingJackson2JsonView view = new MappingJackson2JsonView();
view.setPrettyPrint(true);
return view;
}
}
PDF View Resolver:
這個視圖解析器使用lowagie iText庫實際生成PDF輸出。還要注意的是實際的視圖,從Spring AbstractPdfView 內部使用 lowagie iText 庫擴展。
com.yiibai.springmvc.viewresolver.PdfView
package com.yiibai.springmvc.viewresolver;
import java.awt.Color;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.view.document.AbstractPdfView;
import com.lowagie.text.Document;
import com.lowagie.text.Element;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;
import com.yiibai.springmvc.model.Pizza;
public class PdfView extends AbstractPdfView {
@Override
protected void buildPdfDocument(Map<String, Object> model,
Document document, PdfWriter writer, HttpServletRequest request,
HttpServletResponse response) throws Exception {
Pizza pizza = (Pizza) model.get("pizza");
PdfPTable table = new PdfPTable(3);
table.getDefaultCell().setHorizontalAlignment(Element.ALIGN\_CENTER);
table.getDefaultCell().setVerticalAlignment(Element.ALIGN\_MIDDLE);
table.getDefaultCell().setBackgroundColor(Color.lightGray);
table.addCell("Name");
table.addCell("Flavor");
table.addCell("Toppings");
table.addCell(pizza.getName());
table.addCell(pizza.getFlavor());
StringBuffer toppings = new StringBuffer("");
for (String topping : pizza.getToppings()) {
toppings.append(topping);
toppings.append(" ");
}
table.addCell(toppings.toString());
document.add(table);
}
}
com.yiibai.springmvc.viewresolver.PdfViewResolver類代碼:
package com.yiibai.springmvc.viewresolver;
import java.util.Locale;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
public class PdfViewResolver implements ViewResolver{
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
PdfView view = new PdfView();
return view;
}
}
XLS View Resolver:
這個視圖解析器是使用Apache POI庫實際生成 Microsoft XLS輸出。還要注意的是實際的視圖,從Spring AbstractExcelView 內部使用 Apache POI庫擴展。
com.yiibai.springmvc.viewresolver.ExcelView
package com.yiibai.springmvc.viewresolver;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.web.servlet.view.document.AbstractExcelView;
import com.yiibai.springmvc.model.Pizza;
public class ExcelView extends AbstractExcelView {
@Override
protected void buildExcelDocument(Map<String, Object> model,
HSSFWorkbook workbook, HttpServletRequest request,
HttpServletResponse response) throws Exception {
Pizza pizza = (Pizza) model.get("pizza");
Sheet sheet = workbook.createSheet("sheet 1");
CellStyle style = workbook.createCellStyle();
style.setFillForegroundColor(IndexedColors.GREY\_40\_PERCENT.index);
style.setFillPattern(CellStyle.SOLID\_FOREGROUND);
style.setAlignment(CellStyle.ALIGN\_CENTER);
Row row = null;
Cell cell = null;
int rowCount = 0;
int colCount = 0;
// Create header cells
row = sheet.createRow(rowCount++);
cell = row.createCell(colCount++);
cell.setCellStyle(style);
cell.setCellValue("Name");
cell = row.createCell(colCount++);
cell.setCellStyle(style);
cell.setCellValue("Flavor");
cell = row.createCell(colCount++);
cell.setCellStyle(style);
cell.setCellValue("Toppings");
// Create data cells
row = sheet.createRow(rowCount++);
colCount = 0;
row.createCell(colCount++).setCellValue(pizza.getName());
row.createCell(colCount++).setCellValue(pizza.getFlavor());
StringBuffer toppings = new StringBuffer("");
for (String topping : pizza.getToppings()) {
toppings.append(topping);
toppings.append(" ");
}
row.createCell(colCount++).setCellValue(toppings.toString());
for (int i = 0; i < 3; i++)
sheet.autoSizeColumn(i, true);
}
}
com.yiibai.springmvc.viewresolver.ExcelViewResolver
package com.yiibai.springmvc.viewresolver;
import java.util.Locale;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
public class ExcelViewResolver implements ViewResolver{
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
ExcelView view = new ExcelView();
return view;
}
}
這是所有 ContentNegotaingViewResolver 需要的配置。
完成這個例子並讓它可以運行,讓我們添加缺少 Spring MVC 配置。
第5步:創建控制器類
下面是一個簡單的基於REST的控制器作爲我們的示例。
com.yiibai.springmvc.controller.AppController
package com.yiibai.springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.yiibai.springmvc.model.Pizza;
@Controller
public class AppController {
@RequestMapping(value="/pizzavalley/{pizzaName}", method = RequestMethod.GET)
public String getPizza(@PathVariable String pizzaName, ModelMap model) {
Pizza pizza = new Pizza(pizzaName);
model.addAttribute("pizza", pizza);
return "pizza";
}
}
第6步:創建初始化類
添加一個初始化類實現WebApplicationInitializer如下圖所示(在這種情況下,作爲替代在 web.xml 中定義的任何 Spring 配置)。在Servlet 3.0的容器啓動時,這個類會被加載並實例及其 onStartup方法將通過servlet容器調用。
com.yiibai.springmvc.configuration.AppInitializer
package com.yiibai.springmvc.configuration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
public class AppInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(AppConfig.class);
ctx.setServletContext(container);
ServletRegistration.Dynamic servlet = container.addServlet(
"dispatcher", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
}
}
更新:請注意,上面的類可以寫成更加簡潔[和它的首選方式],通過擴展 AbstractAnnotationConfigDispatcherServletInitializer 基類,如下所示:
package com.yiibai.springmvc.configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>\[\] getRootConfigClasses() {
return new Class\[\] { AppConfig.class };
}
@Override
protected Class<?>\[\] getServletConfigClasses() {
return null;
}
@Override
protected String\[\] getServletMappings() {
return new String\[\] { "/" };
}
}
第7步:構建和部署應用程序
現在構建 war(通過Eclipse或Maven [ mvn clean install])。部署 war 到Servlet3.0容器。
運行。以下是運行示例觸發不同模式輸出的快照(注意URL擴展),訪問如下URL: http://localhost:8080/ContentNegotiatingViewResolver/pizzavalley/margherita.xml
到這裏,所有教程講解完畢!
代碼下載:http://pan.baidu.com/s/1skqkZBf