原文地址:http://websystique.com/springmvc/spring-4-mvc-contentnegotiatingviewresolver-example/
【本系列其他教程正在陆续翻译中,点击分类:spring 4 mvc 进行查看。源码下载地址在文章末尾。】
【翻译 by 明明如月 QQ 605283073】
下一篇:Spring 4 MVC @RestController 注解实现REST Service
上一篇:Spring 4 MVC 表单校验资源处理(带源码)
本文讲述Spring 4 MVC应用中通过Spring的 ContentNegotiatingViewResolver来支持多种形式的输出。
我们将输出 XML, JSON, PDF, XLS 和HTML格式的文件,基于纯注解的方式。
ContentNegotiatingViewResolver
是一个实现了 ViewResolver接口的类
, 使用了请求媒体类型 (根据文件拓展吗 URL 指定输出类型参数或者accept 头)来选择合适的视图. ContentNegotiatingViewResolver 并不是自己进行处理而是代理到其他的ViewResolver 你可以配置处理的特定视图(XML,JSON,PDF,XLS,HTML,..).
------------------------------------------------
使用的技术或者软件
让我们开始吧
------------------------------------
下面是最终的效果:
我们将使用纯注解的方式。
4.0.0
com.websystique.springmvc
Spring4MVCContentNegotiatingViewResolverExample
war
1.0.0
Spring4MVCContentNegotiatingViewResolverExample
4.0.6.RELEASE
org.springframework
spring-core
${springframework.version}
org.springframework
spring-web
${springframework.version}
org.springframework
spring-webmvc
${springframework.version}
org.springframework
spring-oxm
${springframework.version}
com.fasterxml.jackson.core
jackson-databind
2.4.1.3
com.fasterxml.jackson.core
jackson-annotations
2.4.1
com.lowagie
itext
4.2.1
org.apache.poi
poi
3.10-beta2
javax.servlet
javax.servlet-api
3.1.0
javax.servlet
jstl
1.2
javax.servlet.jsp
javax.servlet.jsp-api
2.3.1
org.apache.maven.plugins
maven-compiler-plugin
3.2
1.6
1.6
org.apache.maven.plugins
maven-war-plugin
2.4
src/main/webapp
Spring4MVCContentNegotiatingViewResolverExample
false
Spring4MVCContentNegotiatingViewResolverExample
spring-oxm
支持 XML 格式的输出 (使用 JAXB2).jackson-databind
& jackson-annotations
提供JSON格式的输出. itext提供
PDF 创建库支持PDF 的输出. Apache POI
帮助创建 XLS 格式的输出
com.websystique.springmvc.configuration.AppConfig
package com.websystique.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.websystique.springmvc.model.Pizza;
import com.websystique.springmvc.viewresolver.ExcelViewResolver;
import com.websystique.springmvc.viewresolver.JsonViewResolver;
import com.websystique.springmvc.viewresolver.Jaxb2MarshallingXmlViewResolver;
import com.websystique.springmvc.viewresolver.PdfViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.websystique.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 resolvers = new ArrayList();
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用来决定请求的media代理到ContentNegotiationStrategy实例集合.默认PathExtensionContentNegotiationStrategy
被请求 (使用url拓展名 e.g. .xls, .pdf,.json..) ,然后是ParameterContentNegotiationStrategy
(使用的请求参数 ‘format=xls’ e.g.), 然后是HeaderContentNegotiationStrategy
(使用HTTP Accept Headers)。
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.ignoreAcceptHeader(true).defaultContentType(
MediaType.TEXT_HTML);
}
在我们的例子中我们将使用基于URL拓展名来决定 媒体类型。
如果没有拓展名我们默认用TEXT_HTML 类处理。
也就是说 未知的拓展名类型我们使用jsp 视图解析器处理。
pizza.jsp 将用来做默认的jsp视图解析器
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Pizza JSP View
NAME
Flavor
Toppings
${pizza.name}
${pizza.flavor}
下一步配置: ContentNegotaionViewResolver
public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(manager);
// Define all possible view resolvers
List resolvers = new ArrayList();
resolvers.add(jaxb2MarshallingXmlViewResolver());
resolvers.add(jsonViewResolver());
resolvers.add(jspViewResolver());
resolvers.add(pdfViewResolver());
resolvers.add(excelViewResolver());
resolver.setViewResolvers(resolvers);
return resolver;
}
我们需要设置ContentNegotiationManager 并注入到spring中,不同的解析器响应不同格式的请求。
XML 视图解析器:
com.websystique.springmvc.viewresolver.Jaxb2MarshallingXmlViewResolver
package com.websystique.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.websystique.springmvc.model.Pizza
package com.websystique.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 toppings = new ArrayList();
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 getToppings() {
return toppings;
}
@XmlElement
public void setToppings(List toppings) {
this.toppings = toppings;
}
}
JSON视图解析器
使用 Spring MappingJackson2JsonView
获取视图将POJO转换为JSON
com.websystique.springmvc.viewresolver.JsonViewResolver
package com.websystique.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视图解析器
此视图解析器是使用 lowagie itext 库来实际输出PDF的。
实际视图拓展自Spring AbstractPdfView,它使用的就是itext库。
com.websystique.springmvc.viewresolver.PdfView
package com.websystique.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.websystique.springmvc.model.Pizza;
public class PdfView extends AbstractPdfView {
@Override
protected void buildPdfDocument(Map 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.websystique.springmvc.viewresolver.PdfViewResolver
package com.websystique.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视图解析器:
使用 Apache POI库产生XLS输出。拓展自Spring AbstractExcelView ,它本身内部使用的就是 Apache POI库。
com.websystique.springmvc.viewresolver.ExcelView
package com.websystique.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.websystique.springmvc.model.Pizza;
public class ExcelView extends AbstractExcelView {
@Override
protected void buildExcelDocument(Map 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.websystique.springmvc.viewresolver.ExcelViewResolver
package com.websystique.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;
}
}
com.websystique.springmvc.controller.AppController
package com.websystique.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.websystique.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";
}
}
com.websystique.springmvc.configuration.AppInitializer
package com.websystique.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("/");
}
}
可简化为下面的类:
package com.websystique.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[] { "/" };
}
}
在tomcat中发布
下面截图是根据url拓展名来作不同的响应
[源码下载地址:http://websystique.com/?smd_process_download=1&download_id=772]
特别说明:此系列教程有的童鞋下载下来运行 经常404 或者改成xml方式以后