This tutorial shows you a Spring MVC Excel Pdf ViewResolver Example by using Spring MVC Content negotiation to generate multiple views of the same resource. It means that this example will generate a excel view (.xls or .xlsx format) or pdf view.
Table of contents:
1. Maven Dependencies
2. Project structure
3. Spring MVC Excel Pdf View Configuration
4. Excel Views
5. PDF View
6. HTML View
7. Deploy Spring MVC Excel Pdf ViewResolver Example
Other interesting posts you may like
Now, we start to build Spring MVC Excel Pdf ViewResolver Example step by step
Maven Dependencies
We need to use the following dependencies that supports to create excel document and pdf document.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
<?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.javabycode.spring.mvc</groupId> <artifactId>Spring-MVC-Excel-Pdf-View-Example</artifactId> <version>1.0.0-SNAPSHOT</version> <name>SPRING-MVC - ${project.artifactId}</name> <url>http://javabycode.com</url> <packaging>war</packaging> <properties> <encoding>UTF-8</encoding> <spring.version>4.3.0.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <!-- xls view --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.14</version> </dependency> <!-- xlsx view --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.14</version> </dependency> <!-- pdf view --> <dependency> <groupId>com.lowagie</groupId> <artifactId>itext</artifactId> <version>2.1.7</version> </dependency> <!-- pdf view --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.9</version> </dependency> <!-- servlet api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> </dependencies> <build> <finalName>excel-pdf-view-example</finalName> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>2.6</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </build> </project> |
Project structure
Spring MVC Excel Pdf View Configuration
We are using the configureViewResolvers method to register the views such as XlsView, XlsxView, XlsxStreamingView and ItextPdfView.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package com.javabycode.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.web.servlet.config.annotation.*; import com.javabycode.view.ItextPdfView; import com.javabycode.view.XlsView; import com.javabycode.view.XlsxStreamingView; import com.javabycode.view.XlsxView; @EnableWebMvc @Configuration @ComponentScan("com.javabycode") public class MyWebConfig extends WebMvcConfigurerAdapter { @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { configurer .defaultContentType(MediaType.TEXT_HTML) .parameterName("type") .favorParameter(true) .ignoreUnknownPathExtensions(false) .ignoreAcceptHeader(false) .useJaf(true); } @Override public void configureViewResolvers(ViewResolverRegistry registry) { registry.jsp("/WEB-INF/views/", ".jsp"); registry.enableContentNegotiation( new XlsView(), new XlsxView(), new XlsxStreamingView(), new ItextPdfView()); } } |
This is the same Spring XML configuration as above.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <mvc:annotation-driven/> <context:component-scan base-package="com.javabycode" /> <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"> <property name="defaultContentType" value="TEXT_HTML"/> <property name="parameterName" value="type"/> <property name="favorParameter" value="true"/> <property name="ignoreUnknownPathExtensions" value="false"/> <property name="ignoreAcceptHeader" value="false"/> <property name="useJaf" value="true"/> </bean> <mvc:view-resolvers> <mvc:content-negotiation> <mvc:default-views> <bean class="com.javabycode.view.XlsView"/> <bean class="com.javabycode.view.XlsxView"/> <bean class="com.javabycode.view.XlsxStreamingView"/> <bean class="com.javabycode.view.ItextPdfView"/> </mvc:default-views> </mvc:content-negotiation> <mvc:jsp prefix="/WEB-INF/views/" suffix=".jsp"/> </mvc:view-resolvers> </beans> |
Notices: we need to use the DispatcherServlet to mapping the request to the correct controller methods. It is the same DispatcherServlet of the previous Spring MVC so it is not mentioned here or you can see it in the source code attachment.
Controller Endpoint
This Fruit POJO is used to add data to the Excel and Pdf document.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
package com.javabycode.model; public class Fruit { private Integer id; private String name; private String produceBy; public Fruit() { } public Fruit(Integer id, String name, String produceby) { this.id = id; this.name = name; this.produceBy = produceby; } public Integer getId() { return id; } public String getName() { return name; } public String getProduceBy() { return produceBy; } } |
The FruitsController is responsible to create list of Fruit elements for Model which be used to display on the Excel and Pdf document.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package com.javabycode.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.javabycode.model.Fruit; import java.util.Arrays; import java.util.List; @Controller @RequestMapping("/fruits") public class FruitsController { List<Fruit> array = Arrays.asList( new Fruit(1, "Banana", "Indonesia"), new Fruit(2, "Orange", "Holland"), new Fruit(3, "Mango", "France") ); @RequestMapping(method = RequestMethod.GET) public String getDocuments(Model model) { model.addAttribute("fruits", array); return "index"; } } |
Excel Views
The Excel document is with 2 extension format, the .xls is the old format and the .xlsx is the new foramt. The apache POI library is responsible to create excel files.
Implement XlsView using AbstractXlsView
The XlsView is extended from AbstractXlsView. Then we override the buildExcelDocument method to create the excel document.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
package com.javabycode.view; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.springframework.web.servlet.view.document.AbstractXlsView; import com.javabycode.model.Fruit; import org.apache.poi.ss.usermodel.Workbook; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.List; import java.util.Map; public class XlsView extends AbstractXlsView { @Override protected void buildExcelDocument(Map<String, Object> model, Workbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception { // set the file name response.setHeader("Content-Disposition", "attachment; filename=\"fruits.xls\""); @SuppressWarnings("unchecked") List<Fruit> fruits = (List<Fruit>) model.get("fruits"); // create sheet Sheet sheet = workbook.createSheet("Fruits Xls"); // create header Row header = sheet.createRow(0); header.createCell(0).setCellValue("No"); header.createCell(1).setCellValue("Name"); header.createCell(2).setCellValue("Produce by"); // Create cells int rowCount = 1; for (Fruit fruit : fruits){ Row fruitRow = sheet.createRow(rowCount++); fruitRow.createCell(0).setCellValue(fruit.getId()); fruitRow.createCell(1).setCellValue(fruit.getName()); fruitRow.createCell(2).setCellValue(fruit.getProduceBy()); } } } |
Implement XlsxView using AbstractXlsxView
Instead of extending the AbstractXlsView, the XlsxView is extended from AbstractXlsxView. The rest part of XlsxView implementation is the same XlsView above.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
package com.javabycode.view; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.springframework.web.servlet.view.document.AbstractXlsxView; import com.javabycode.model.Fruit; import org.apache.poi.ss.usermodel.Workbook; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.List; import java.util.Map; public class XlsxView extends AbstractXlsxView { @Override protected void buildExcelDocument(Map<String, Object> model, Workbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception { // set the file name response.setHeader("Content-Disposition", "attachment; filename=\"fruits.xlsx\""); @SuppressWarnings("unchecked") List<Fruit> fruits = (List<Fruit>) model.get("fruits"); // create sheet Sheet sheet = workbook.createSheet("Fruits Xlsx"); // create header Row header = sheet.createRow(0); header.createCell(0).setCellValue("No"); header.createCell(1).setCellValue("Name"); header.createCell(2).setCellValue("Provided by"); // Create cells int rowCount = 1; for (Fruit fruit : fruits){ Row fruitRow = sheet.createRow(rowCount++); fruitRow.createCell(0).setCellValue(fruit.getId()); fruitRow.createCell(1).setCellValue(fruit.getName()); fruitRow.createCell(2).setCellValue(fruit.getProduceBy()); } } } |
Implement XLSX Streaming View
If you need to process large excel documents you should use AbstractXlsxStreamingView. The StreamingView will improve the performance of large documents. Notice that some clients are incompatible with this streaming way. So you should consider to use.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
package com.javabycode.view; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.springframework.web.servlet.view.document.AbstractXlsxStreamingView; import com.javabycode.model.Fruit; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.List; import java.util.Map; public class XlsxStreamingView extends AbstractXlsxStreamingView { @Override protected void buildExcelDocument(Map<String, Object> model, Workbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception { // set the file name response.setHeader("Content-Disposition", "attachment; filename=\"fruits.xlsx\""); @SuppressWarnings("unchecked") List<Fruit> fruits = (List<Fruit>) model.get("fruits"); // create sheet Sheet sheet = workbook.createSheet("Fruits Xlsx streaming"); // create header Row header = sheet.createRow(0); header.createCell(0).setCellValue("No"); header.createCell(1).setCellValue("Name"); header.createCell(2).setCellValue("Provided by"); // Create cells int rowCount = 1; for (Fruit fruit : fruits){ Row fruitRow = sheet.createRow(rowCount++); fruitRow.createCell(0).setCellValue(fruit.getId()); fruitRow.createCell(1).setCellValue(fruit.getName()); fruitRow.createCell(2).setCellValue(fruit.getProduceBy()); } } } |
PDF view
The new com.itextpdf:itextpdf library is not supported by default. We will create an abstract class and extending from the AbstractView to resolve this issue. The abstract class should be implemented such as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
package com.javabycode.view; import java.io.ByteArrayOutputStream; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.view.AbstractView; import com.itextpdf.text.Document; import com.itextpdf.text.PageSize; import com.itextpdf.text.pdf.PdfWriter; public abstract class AbstractPdfView extends AbstractView { public AbstractPdfView() { setContentType("application/pdf"); } protected void buildPdfMetadata(Map<String, Object> model, Document document, HttpServletRequest request) { } protected abstract void buildPdfDocument(Map<String, Object> model, Document document, PdfWriter writer, HttpServletRequest request, HttpServletResponse response) throws Exception; @Override protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { ByteArrayOutputStream out = createTemporaryOutputStream(); Document document = new Document(PageSize.A4); PdfWriter writer = PdfWriter.getInstance(document, out); writer.setViewerPreferences(PdfWriter.ALLOW_PRINTING | PdfWriter.PageLayoutSinglePage); buildPdfMetadata(model, document, request); document.open(); buildPdfDocument(model, document, writer, request, response); document.close(); writeToResponse(response, out); } @Override protected boolean generatesDownloadContent() { return true; } } |
The buildPdfMetadata and buildPdfDocument methods are responsible to create the Pdf document. And the renderMergedOutputModel(..) method are responsible to write the pdf document to the response.
Then, we need to create new class ItextPdfView that extends from the AbstractPdfView class and override the buildPdfDocument method to create the real pdf document.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package com.javabycode.view; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.itextpdf.text.Document; import com.itextpdf.text.pdf.PdfPTable; import com.itextpdf.text.pdf.PdfWriter; import com.javabycode.model.Fruit; public class ItextPdfView extends AbstractPdfView { @Override protected void buildPdfDocument(Map<String, Object> model, Document document, PdfWriter writer, HttpServletRequest request, HttpServletResponse response) throws Exception { @SuppressWarnings("unchecked") List<Fruit> fruits = (List<Fruit>) model.get("fruits"); PdfPTable table = new PdfPTable(3); table.setWidths(new int[] { 20, 50, 100 }); table.addCell("No"); table.addCell("Name"); table.addCell("Provided by"); for (Fruit fruit : fruits) { table.addCell(String.valueOf(fruit.getId())); table.addCell(fruit.getName()); table.addCell(fruit.getProduceBy()); } document.add(table); } } |
HTML View
The text/html is the default view and this view will be displayed using the same URI.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<%@ 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" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <html> <head> <title>Spring MVC Excel Pdf View</title> </head> <body> <table> <tr> <th width="20px">No</th> <th width="50px">Name</th> <th width="100px">Provided By</th> </tr> <c:forEach var="c" items="${fruits}"> <tr> <td>${c.id}</td> <td>${c.name}</td> <td>${c.produceBy}</td> </tr> </c:forEach> </table> </body> </html> |
Deploy Spring MVC Excel Pdf ViewResolver Example
Building project with maven then deploy file war on application server or servlet container (Tomcat 8 for example). Access the address URL http://localhost:8080/excel-pdf-view-example/fruits and the screen will display such as the picture
Access the address URL http://localhost:8080/excel-pdf-view-example/fruits.xls then the browser render the fruits.xls file. Or ccess the address URL http://localhost:8080/excel-pdf-view-example/fruits.xlsx then the browser render the fruits.xlsx file as below
Access the address URL http://localhost:8080/excel-pdf-view-example/fruits.pdf then the browser render the fruits.pdf file as below
That’s it on how to create Spring MVC Excel Pdf ViewResolver Example. The next post will show you how to view JSON and XML using Spring MVC Content negotiation.
Download complete source code of example, please click link below
Spring-MVC-Excel-Pdf-ViewResolver-Example.zip (569 downloads)
Source code on Github https://github.com/javabycode/spring-mvc-excel-pdf-viewresolver-example