Spring MVC with CSV File Download Example
- Details
- Written by Nam Ha Minh
- Last Updated on 02 September 2020   |   Print Email
This Spring tutorial provides some examples of implementing CSV file download functionality in a Spring MVC application. The CSV library to be used is Super CSV - an open source package that provides fast and powerful manipulation of CSV format.
NOTE: For Spring Boot, refer to this article Spring Boot Export Data to CSV Example
On the Spring side, we cover two approaches to build the CSV file download functionality:
- Handling CSV generation and download in a separate controller class. This is the simplest and quickest way. The technique employed is similar to the one described in the tutorial: Spring MVC file download example. The difference is that we use an external CSV library for generating CSV data from model data, before pushing the data to the client.
- Subclassing the Spring’s AbstractView class to create a new CSV View class. This is more complex but flexible in terms of integration and reusability with Spring’s view resolvers. The technique is well described in the tutorial Spring Web MVC with PDF View Example.
Let’s look at the model data first. Suppose that we have the following model class (Book.java):
package net.codejava.spring.model; public class Book { private String title; private String description; private String author; private String publisher; private String isbn; private String publishedDate; private float price; public Book() { } public Book(String title, String description, String author, String publisher, String isbn, String publishedDate, float price) { this.title = title; this.description = description; this.author = author; this.publisher = publisher; this.isbn = isbn; this.publishedDate = publishedDate; this.price = price; } // getters and setters... }
Therefore, our purpose is to create a Spring MVC application that is able to generate a CSV file from a list of Books, and then push it back to the client for downloading. Now, let’s dive into each approach in details.
1. Approach #1: Coding a CSV File Download Controller
In this approach, we create a Spring controller class that handles everything like this:
package net.codejava.spring.controller; import java.io.IOException; import java.util.Arrays; import java.util.List; import javax.servlet.http.HttpServletResponse; import net.codejava.spring.model.Book; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.supercsv.io.CsvBeanWriter; import org.supercsv.io.ICsvBeanWriter; import org.supercsv.prefs.CsvPreference; /** * This Spring controller class implements a CSV file download functionality. * @author www.codejava.net * */ @Controller public class CSVFileDownloadController { @RequestMapping(value = "/downloadCSV") public void downloadCSV(HttpServletResponse response) throws IOException { String csvFileName = "books.csv"; response.setContentType("text/csv"); // creates mock data String headerKey = "Content-Disposition"; String headerValue = String.format("attachment; filename=\"%s\"", csvFileName); response.setHeader(headerKey, headerValue); Book book1 = new Book("Effective Java", "Java Best Practices", "Joshua Bloch", "Addision-Wesley", "0321356683", "05/08/2008", 38); Book book2 = new Book("Head First Java", "Java for Beginners", "Kathy Sierra & Bert Bates", "O'Reilly Media", "0321356683", "02/09/2005", 30); Book book3 = new Book("Thinking in Java", "Java Core In-depth", "Bruce Eckel", "Prentice Hall", "0131872486", "02/26/2006", 45); Book book4 = new Book("Java Generics and Collections", "Comprehensive guide to generics and collections", "Naftalin & Philip Wadler", "O'Reilly Media", "0596527756", "10/24/2006", 27); List<Book> listBooks = Arrays.asList(book1, book2, book3, book4); // uses the Super CSV API to generate CSV data from the model data ICsvBeanWriter csvWriter = new CsvBeanWriter(response.getWriter(), CsvPreference.STANDARD_PREFERENCE); String[] header = { "Title", "Description", "Author", "Publisher", "isbn", "PublishedDate", "Price" }; csvWriter.writeHeader(header); for (Book aBook : listBooks) { csvWriter.write(aBook, header); } csvWriter.close(); } }
As we can see, the downloadCSV() method handles requests with the URL: /downloadCSV. It creates some mock data (a list of Book objects), and then uses the Super CSV API to generate the CSV data. There are 3 important points here:
- Setting the response’s content type to text/csv:
response.setContentType("text/csv");
- Wrapping the response’s writer object inside the CsvBeanWriter:
ICsvBeanWriter csvWriter = new CsvBeanWriter(response.getWriter(), ...);
- And finally closing the CSV writer in order to push the data to the client:
csvWriter.close();
2. Approach #2: Subclassing AbstractView class
This approach involves in creating an abstract view class, a concrete view class, configuring a view properties file and a view resolver. And finally, create a controller method.
Coding the abstract CSV view (AbstractCsvView.java):
Subclass the Spring’s AbstractView class by writing the following class:
package net.codejava.spring.view; import java.io.IOException; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.view.AbstractView; import org.supercsv.io.CsvBeanWriter; import org.supercsv.io.ICsvBeanWriter; import org.supercsv.prefs.CsvPreference; /** * This class is an abstract CSV view which concrete views must implement. * @author www.codejava.net * */ public abstract class AbstractCsvView extends AbstractView { private String fileName; public void setFileName(String fileName) { this.fileName = fileName; } protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) { String headerKey = "Content-Disposition"; String headerValue = String.format("attachment; filename=\"%s\"", fileName); response.setContentType("text/csv"); response.setHeader(headerKey, headerValue); } @Override protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { ICsvBeanWriter csvWriter = new CsvBeanWriter(response.getWriter(), CsvPreference.STANDARD_PREFERENCE); buildCsvDocument(csvWriter, model); csvWriter.close(); } /** * The concrete view must implement this method. */ protected abstract void buildCsvDocument(ICsvBeanWriter csvWriter, Map<String, Object> model) throws IOException; }
This abstract class implements some skeleton code to write CSV data to the response, and leaves the task of building the CSV document to implementers by declaring the abstract method buildCsvDocument().
Coding the concrete CSV view (CsvViewImpl.java):
Write an implementation of the AbstractCsvView class and make it implements the buildCsvDocument() method as follows:
package net.codejava.spring.view; import java.io.IOException; import java.util.List; import java.util.Map; import net.codejava.spring.model.Book; import org.supercsv.io.ICsvBeanWriter; /** * An implementation of the AbstractCsvView. * This decides what model data to be used to generate CSV data. * @author www.codejava.net * */ public class CsvViewImpl extends AbstractCsvView { @Override protected void buildCsvDocument(ICsvBeanWriter csvWriter, Map<String, Object> model) throws IOException { List<Book> listBooks = (List<Book>) model.get("csvData"); String[] header = (String[]) model.get("csvHeader"); csvWriter.writeHeader(header); for (Book aBook : listBooks) { csvWriter.write(aBook, header); } } }
As we can see, this concrete CSV view takes data from the model under the keys “csvData” and “csvHeader” and use the supplied CSV writer to generate the CSV data.
Configuring a view properties file (views.properties):
To use the CsvViewImpl class above, we need to create a properties file under the project’s classpath with the following content (views.properties):
ViewCSV.(class)=net.codejava.spring.view.CsvViewImpl ViewCSV.fileName=JavaBooks.csv
Here, ViewCSV is the view name which will be resolved by a view resolver; the (class) attribute specifies the view implementation class and the fileName attribute specifies name of the CSV file to be sent to the client.
Configuring a view resolver:
If Java config is used, add the following method to your configuration class:
@Bean public ViewResolver getCsvViewResolver(){ ResourceBundleViewResolver resolver = new ResourceBundleViewResolver(); resolver.setBasename("views"); resolver.setOrder(1); return resolver; }
That’s equivalent to the following XML descriptor (in case you are using XML configuration):
<bean id="csvViewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver"> <property name="order" value="1"/> <property name="basename" value="views"/> </bean>
Coding a Spring controller method:
And finally, add the following method into your controller class:
@RequestMapping(value="/viewCSV") public ModelAndView viewCSV(HttpServletResponse response) throws IOException { Book book1 = new Book("Effective Java", "Java Best Practices", "Joshua Bloch", "Addision-Wesley", "0321356683", "05/08/2008", 38); Book book2 = new Book("Head First Java", "Java for Beginners", "Kathy Sierra & Bert Bates", "O'Reilly Media", "0321356683", "02/09/2005", 30); Book book3 = new Book("Thinking in Java", "Java Core In-depth", "Bruce Eckel", "Prentice Hall", "0131872486", "02/26/2006", 45); Book book4 = new Book("Java Generics and Collections", "Comprehensive guide to generics and collections", "Naftalin & Philip Wadler", "O'Reilly Media", "0596527756", "10/24/2006", 27); List<Book> listBooks = Arrays.asList(book1, book2, book3, book4); String[] header = { "Title", "Description", "Author", "Publisher", "isbn", "PublishedDate", "Price" }; ModelAndView model = new ModelAndView("ViewCSV"); model.addObject("csvData", listBooks); model.addObject("csvHeader", header); return model; }
This method simply creates some mock data and passes it into the model. And the rest is handled by the view resolver and view class which we created previously.
3. Coding Test Home Page
To test both approaches, write the home.jsp page with the following content:
<%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Spring MVC with CSV File Download Example</title> </head> <body> <div align="center"> <h1>Spring MVC with CSV File Download</h1> <p><a href="/downloadCSV">Download CSV #1</a></p> <p><a href="/viewCSV">Download CSV #2</a></p> </div> </body> </html>
This page simply displays two hyperlinks: the first one to download a CSV file using the first approach, and the second one uses the second approach.
4. Eclipse Project Structure and Maven Dependencies
For your reference, the following screenshot is the Maven project structure in Eclipse IDE:
To create this kind of project, you can follow this tutorial: Creating a Spring MVC project using Maven and Eclipse in one minute.
And update the pom.xml file for the latest releases of Java, Spring, Servlet API and Super CSV:
- For Java 7 and Spring 3.2.5.RELEASE:
<properties> <java.version>1.7</java.version> <spring.version>3.2.5.RELEASE</spring.version> <cglib.version>2.2.2</cglib.version> </properties>
- For Servlet 3.0 API:
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency>
- For Super CSV library:
<dependency> <groupId>net.sf.supercsv</groupId> <artifactId>super-csv</artifactId> <version>2.1.0</version> </dependency>
5. Testing the Spring MVC CSV File Download Application
Let’s deploy the application on a Servlet container like Tomcat, and type the following URL in browser:
http://localhost:8080/SpringMvcCSVFileDownloadExample
The default page gets displayed as follows:
Click on the first hyperlink, the browser will download the books.csv file, whereas the second link will cause the JavaBooks.csv to be downloaded. Here is content of the generated CSV file (some text is truncated for brevity):
Title,Description,Author,Publisher,isbn,PublishedDate,Price Effective Java,Java Best Practices,Joshua Bloch,Addision-Wesley,0321356683,05/08/2008,38.0 Head First Java,Java for Beginners,Kathy Sierra...,O'Reilly Media,0321356683,02/09/2005,30.0 Thinking in Java,Java Core In-depth,Bruce Eckel,Prentice Hall,0131872486,02/26/2006,45.0 Java Generics...,Comprehensive guide...,Naftalin ...,O'Reilly Media,0596527756,10/24/2006,27.0
NOTE: If you're looking for CSV export example in Spring Boot, I recommend you to follow this article: Spring Boot Export Data to CSV Example
Related Spring View Tutorials:
- Spring MVC URL-based View Resolution with UrlFilenameViewController Example
- Parameterize View Name with ParameterizableViewController in Spring MVC
- Spring MVC with Excel View Example
- Spring MVC with PDF View Example
Other Spring Tutorials:
- Understand the core of Spring framework
- Understand Spring MVC
- Understand Spring AOP
- Spring MVC beginner tutorial with Spring Tool Suite IDE
- Spring MVC Form Handling Tutorial
- Spring MVC Form Validation Tutorial
- Spring MVC JdbcTemplate Example
- 14 Tips for Writing Spring MVC Controller
- Spring Web MVC Security Basic Example (XML Configuration)
- Understand Spring Data JPA with Simple Example
Comments
Which URL do you want to mean? URL of this tutorial, or URL of the sample webapp? or else?