A Comma-Separated Values (CSV) file is a plain text file that uses a comma as a delimiter to separate values. It stores data in a tabular format where each row consists of one or more fields, and each column represents a specific field.
CSV is a widely used data exchange format in the industry due to its simplicity and better integration with existing applications. These files are usually used for exporting and importing large data sets.
In this tutorial, we shall learn how to export and download the data as a CSV file in a Spring Boot project. Data export (JSON, CSV, PDF, etc.) is a common feature implemented in many Java enterprise applications.
Project Dependencies
Since Java does not provide native support for creating and parsing CSV files, we shall use OpenCSV, a 3rd-party library for parsing and creating CSV files.
Here is what our build.gradle
file looks like:
build.gradle
plugins {
id 'org.springframework.boot' version '2.1.3.RELEASE'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
group = 'com.attacomsian'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.opencsv:opencsv:4.5'
}
If you are working with a maven project, make sure you include the following maven dependency to the project's pom.xml
file:
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>4.5</version>
</dependency>
User Model
Here is our User
model class being used to write to a CSV file.
User.java
package com.attacomsian.exportcsv.data;
import com.opencsv.bean.CsvBindByName;
import com.opencsv.bean.CsvBindByPosition;
public class User {
private long id;
private String name;
private String email;
private String country;
private int age;
public User(long id, String name, String email, String country, int age) {
this.id = id;
this.name = name;
this.email = email;
this.country = country;
this.age = age;
}
// getters and setters removed for the sake of brevity
}
Since we want to generate a CSV file from a list of users and then return it to the client for downloading, let's create a dummy service that acts as a data source and returns a list of users.
UserService.java
package com.attacomsian.exportcsv.data;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class UserService {
public List<User> listUsers() {
List<User> users = new ArrayList<>();
//create dummy users
users.add(new User(1, "Jack Lee", "jack@example.com", "Germany", 35));
users.add(new User(2, "Jovan Srovoki", "jovan@srovoki.me", "Russia", 21));
users.add(new User(3, "Atta", "atta@gmail.com", "Pakistan", 29));
return users;
}
}
The UserService
above is just for demo purposes. You may want to populate a list of users from the database or any other source.
Generate & Download CSV File
The following Spring MVC controller class handles the export and download of data as a CSV file.
UserController.java
package com.attacomsian.exportcsv.controllers;
import com.attacomsian.exportcsv.data.User;
import com.attacomsian.exportcsv.data.UserService;
import com.opencsv.CSVWriter;
import com.opencsv.bean.ColumnPositionMappingStrategy;
import com.opencsv.bean.StatefulBeanToCsv;
import com.opencsv.bean.StatefulBeanToCsvBuilder;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import javax.servlet.http.HttpServletResponse;
@Controller
public class UserController {
private UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/export-users")
public void exportCSV(HttpServletResponse response) throws Exception {
//set file name and content type
String filename = "users.csv";
response.setContentType("text/csv");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + filename + "\"");
//create a csv writer
StatefulBeanToCsv<User> writer = new StatefulBeanToCsvBuilder<User>(response.getWriter())
.withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
.withSeparator(CSVWriter.DEFAULT_SEPARATOR)
.withOrderedResults(false)
.build();
//write all users to csv file
writer.write(userService.listUsers());
}
}
The above UserController
class contains an exportCSV()
method that is mapped to /export-users
HTTP route and returns a CSV file as attachment for browser to download. This method does the following:
- Set the response's content type to
text/csv
. - Use
HttpHeaders.CONTENT_DISPOSITION
to add"Content-Disposition"
response header that indicates file attachment to the browser. It also sets the attachment file name tousers.csv
- Use response writer (
response.writer()
returns an object of typePrintWriter
) to build an instance ofStatefulBeanToCsv
. - Use
write()
method ofStatefulBeanToCsv
instance to write a list of users to CSV file. - Afterwards, the data is pushed to the client where the browser downloads the attached
users.csv
file.
Running the Application
Below is the main application class used for running the Spring Boot project:
Application.java
package com.attacomsian.exportcsv;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Let's run the application by typing the following command in your terminal from the root directory of the project:
$ ./gradlew bootRun
After the Spring Boot application is started, open http://localhost:8080/export-users link in your favorite browser to generate and download the users.csv
file. Here is the content of the generated CSV file:
users.csv
age,country,email,id,name
35,Germany,jack@example.com,1,Jack Lee
21,Russia,jovan@srovoki.me,2,Jovan Srovoki
29,Pakistan,atta@gmail.com,3,Atta
Notice the first line. OpenCSV automatically generated column headers using User
class members. Another thing to note is the order of the columns in the CSV file. OpenCSV sorts the column names in ascending order before writing them into the CSV file.
OpenCSV Columns Ordering
There is no built-in functionality in OpenCSV that allows writing bean to CSV with custom column names and ordering. However, using the @CsvBindByPosition
annotation, you can control the column positions in the generated CSV file. But the downside of this annotation is that it removes column headers from the generated CSV file.
public class User {
@CsvBindByPosition(position = 0)
private long id;
@CsvBindByPosition(position = 1)
private String name;
@CsvBindByPosition(position = 2)
private String email;
@CsvBindByPosition(position = 3)
private String country;
@CsvBindByPosition(position = 4)
private int age;
//constructor, getting and settings
}
@CsvBindByPosition
specifies a binding between a column number of the CSV file and a field in a bean. This column number is zero-based (means position
starts from 0
).
Source code: Download the complete source code from GitHub available under MIT license.
Conclusion
That's all for explaining the usage of the OpenCSV library to generate and download a CSV file in Spring Boot. If you are uncomfortable using a 3rd-party library, you can write your own CSV writer. Writing a CSV file is similar to writing a text file with few exceptions.
Further Reading
If you like this article, don't forget to read the below CSV-related articles:
- Uploading and Parsing CSV File using Spring Boot
- Reading and writing CSV files using OpenCSV
- Reading and writing CSV files using core Java
- Reading and writing CSV files using Apache Commons CSV
- How to read and parse a CSV file in Java
✌️ Like this article? Follow me on Twitter and LinkedIn. You can also subscribe to RSS Feed.