Spring 4 MVC 视图解析器(XML JSON PDF等) 纯注解(带源码)【推荐】

原文地址: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,..).

------------------------------------------------

使用的技术或者软件

  • 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 4 MVC 视图解析器(XML JSON PDF等) 纯注解(带源码)【推荐】_第1张图片


我们将使用纯注解的方式。

第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.websystique.springmvc</groupId>
    <artifactId>Spring4MVCContentNegotiatingViewResolverExample</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-compiler-plugin</artifactId>
                    <version>3.2</version>
                    <configuration>
                        <source>1.6</source>
                        <target>1.6</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>2.4</version>
                    <configuration>
                        <warSourceDirectory>src/main/webapp</warSourceDirectory>
                        <warName>Spring4MVCContentNegotiatingViewResolverExample</warName>
                        <failOnMissingWebXml>false</failOnMissingWebXml>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
 
        <finalName>Spring4MVCContentNegotiatingViewResolverExample</finalName>
    </build>
</project>


spring-oxm 支持 XML 格式的输出 (使用 JAXB2).jackson-databind & jackson-annotations 提供JSON格式的输出. itext提供PDF 创建库支持PDF 的输出. Apache POI 帮助创建 XLS 格式的输出

第3步:创建Spring配置类

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<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用来决定请求的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" %>
 
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <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中,不同的解析器响应不同格式的请求。

第4步: 创建不同的视图解析器

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<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视图解析器


使用 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<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.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<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.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;
      }
     
}

第5步: 创建控制器类

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";
  
    }
     
}


第6步:创建初始化类


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[] { "/" };
    }
 
}

Step 7:创建和发布

在tomcat中发布

下面截图是根据url拓展名来作不同的响应
Spring 4 MVC 视图解析器(XML JSON PDF等) 纯注解(带源码)【推荐】_第2张图片



Spring 4 MVC 视图解析器(XML JSON PDF等) 纯注解(带源码)【推荐】_第3张图片

Spring 4 MVC 视图解析器(XML JSON PDF等) 纯注解(带源码)【推荐】_第4张图片

Spring 4 MVC 视图解析器(XML JSON PDF等) 纯注解(带源码)【推荐】_第5张图片


[源码下载地址:http://websystique.com/?smd_process_download=1&download_id=772]

你可能感兴趣的:(spring,json,mvc,xml,pdf,4)