一直对ContentNegotiatingViewResolver(协商资源表述)一知半解,今天花了点时写了个小例子间彻底弄明白
这个其实是一个中间代理,本身不解析视图,它只会根据请求的信息调用对应的视图解析器处理请求,返回如jsp,json,xml,pdf,excel等,它会首先查看URL的文件扩展名。如果URL在结尾处有文件扩展名的话,ContentNegotiatingViewResolver将会基于该扩展名确定所需的类型。如果扩展名是“.json”的话,那么所需的内容类型必须是“application/json”。如果扩展名是“.xml”,那么客户端请求的就是“application/xml”。当然,“.html”扩展名表明客户端所需的资源表述为HTML(text/html)。如果没有Accept头部信息,并且扩展名也无法提供帮助的话,将会使用“/”作为默认的内容类型,这就意味着客户端必须要接收服务器发送的任何形式的表述(翻译自Spring In Action 第四版)。
其实这个类现在用的很少,基本上都是用@RestController和Http消息转换来做的
本例用到的工具和主要jar包如下:
Spring 4.3.11.RELEASE
jackson-databind 2.9.1
jackson-annotations 2.9.1
lowagie itext 4.2.1
Apache POI 3.17
Maven 3
JDK 1.8
Tomcat 8.5.20
Eclipse Oxygen
Step 1: 创建项目目录结构如下
Step 2: pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lyl</groupId>
<artifactId>springmvc-rest</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>springmvc-rest</name>
<description>Demo REST API Webapp Project for Spring Annotation</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<junit.version>4.12</junit.version>
<spring.version>4.3.11.RELEASE</spring.version>
<jstl.version>1.2</jstl.version>
<servlet.version>3.1.0</servlet.version>
<log4j2.version>2.9.0</log4j2.version>
<slf4j.version>1.7.25</slf4j.version>
<lombok.version>1.16.12</lombok.version>
<jackson.version>2.9.1</jackson.version>
</properties>
<dependencies>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<!-- junit config -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.6</version>
</dependency>
<!-- spring context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring-oxm -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j2.version}</version>
</dependency>
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<!-- jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.lowagie/itext -->
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.7</version>
</dependency>
</dependencies>
<build>
<finalName>springmvc-rest</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<fork>true</fork>
<verbose>true</verbose>
<encoding>UTF-8</encoding>
<compilerArguments>
<sourcepath>${project.basedir}/src/main/java</sourcepath>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
Step 3: 配置类
1.WebAppInitializer
package com.lyl.springmvc.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { RootConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
2.WebConfig
package com.lyl.springmvc.config;
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.DefaultServletHandlerConfigurer;
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.lyl.springmvc.config.viewresolver.ExcelViewResolver;
import com.lyl.springmvc.config.viewresolver.Jaxb2MarshallingXmlViewResolver;
import com.lyl.springmvc.config.viewresolver.JsonViewResolver;
import com.lyl.springmvc.config.viewresolver.PdfViewResolver;
import com.lyl.springmvc.model.Person;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.lyl.springmvc.controller")
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
/*
* 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(jspViewResolver());
resolvers.add(jsonViewResolver());
resolvers.add(jaxb2MarshallingXmlViewResolver());
resolvers.add(excelViewResolver());
resolvers.add(pdfViewResolver());
resolver.setViewResolvers(resolvers);
return resolver;
}
/*
* 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 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;
}
/*
* 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(Person.class);
return new Jaxb2MarshallingXmlViewResolver(marshaller);
}
/*
* 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 PDF output using lowagie pdf library to generate PDF output for an object content
*/
@Bean
public ViewResolver pdfViewResolver() {
return new PdfViewResolver();
}
}
3.RootConfig
package com.lyl.springmvc.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@ComponentScan(basePackages = "com.lyl.springmvc", excludeFilters = { @Filter({ Controller.class, EnableWebMvc.class }) })
public class RootConfig {
}
Step 4: 创建ViewResolver类
1.XML
package com.lyl.springmvc.config.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;
}
}
2.JSON
package com.lyl.springmvc.config.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;
}
}
3.PDF
package com.lyl.springmvc.config.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.lyl.springmvc.model.Person;
public class PdfView extends AbstractPdfView {
@Override
protected void buildPdfDocument(Map<String, Object> model, Document document, PdfWriter writer, HttpServletRequest request,
HttpServletResponse response) throws Exception {
Person p = (Person) model.get("p");
PdfPTable table = new PdfPTable(3);
table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
table.getDefaultCell().setVerticalAlignment(Element.ALIGN_MIDDLE);
table.getDefaultCell().setBackgroundColor(Color.lightGray);
table.addCell("ID");
table.addCell("NAME");
table.addCell("AGE");
table.addCell(String.valueOf(p.getId()));
table.addCell(p.getName());
table.addCell(String.valueOf(p.getAge()));
document.add(table);
}
}
package com.lyl.springmvc.config.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;
}
}
3.EXCEL
package com.lyl.springmvc.config.viewresolver;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.web.servlet.view.document.AbstractXlsxView;
import com.lyl.springmvc.model.Person;
public class ExcelView extends AbstractXlsxView {
@Override
protected void buildExcelDocument(Map<String, Object> model, Workbook workbook, HttpServletRequest request, HttpServletResponse response)
throws Exception {
Person p = (Person) model.get("p");
Sheet sheet = workbook.createSheet("sheet 1");
CellStyle style = workbook.createCellStyle();
style.setFillForegroundColor(IndexedColors.GREY_40_PERCENT.index);
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
style.setAlignment(HorizontalAlignment.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("ID");
cell = row.createCell(colCount++);
cell.setCellStyle(style);
cell.setCellValue("NAME");
cell = row.createCell(colCount++);
cell.setCellStyle(style);
cell.setCellValue("AGE");
// Create data cells
row = sheet.createRow(rowCount++);
colCount = 0;
row.createCell(colCount++).setCellValue(p.getId());
row.createCell(colCount++).setCellValue(p.getName());
row.createCell(colCount++).setCellValue(p.getAge());
}
}
package com.lyl.springmvc.config.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;
}
}
Step 5: 控制器类
package com.lyl.springmvc.controller;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import com.lyl.springmvc.model.Person;
import com.lyl.springmvc.service.PersonService;
@Controller
@RequestMapping("/person")
public class PersonController {
@Autowired
private PersonService pService;
@RequestMapping("/{id}")
public String findPerson(@PathVariable Integer id, Map<String, Person> model) {
model.put("p", pService.getById(id));
return "/person/details";
}
@RequestMapping(value = {"/", "/list"})
public String findPersonList(Map<String, List<Person>> model) {
model.put("ps", pService.getAll());
return "/person/list";
}
}
Step 6: Service 和 Model类
package com.lyl.springmvc.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Service;
import com.lyl.springmvc.model.Person;
@Service
public class PersonService {
private Map<Integer, Person> personMap = new HashMap<Integer, Person>();
public PersonService() {
personMap.put(1, new Person(1, "Tom", 18));
personMap.put(2, new Person(2, "Jack", 20));
personMap.put(3, new Person(3, "Andy", 17));
}
public Person getById(Integer id) {
return personMap.get(id);
}
public List<Person> getAll() {
return new ArrayList<Person>(personMap.values());
}
}
package com.lyl.springmvc.model;
import javax.xml.bind.annotation.XmlRootElement;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@XmlRootElement(name = "person")
public class Person {
private Integer id;
private String name;
private int age;
public Person() {
}
public Person(Integer id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
}
Step 7: 部署测试
1.http://localhost:8080/springmvc-rest/person/list
默认请求不带后缀直接返回jsp页面
2.http://localhost:8080/springmvc-rest/person/list.json
返回JSON格式
2.http://localhost:8080/springmvc-rest/person/list.xml
返回xml格式
3.http://localhost:8080/springmvc-rest/person/list.pdf
返回PDF
4.http://localhost:8080/springmvc-rest/person/list.xlsx
返回EXCEL
本文参考资料
1.Spring In Action 第四版第16章
2.https://websystique.com/springmvc/spring-4-mvc-contentnegotiatingviewresolver-example/