A Comma-Separated Values (CSV) file is just a simple plain text file that uses a comma as delimiter to separate values. It stores data in tabular format where each row consists of one or more fields and each column represents a specific field. These fields are separated by commas, one of the reasons why these files are called comma-separated values.

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 will learn how to export and download the data as CSV file in a Spring Boot project. Data export (JSON, CSV, PDF etc.) is a very common feature implemented in many Java enterprise applications.

Project Dependencies

Since Java does not provide native support for creating and parsing CSV files, we will use OpenCSV 3rd-party library for this purpose. Here is how 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 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 that will be used to write to 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 back to 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 purpose. You may want to populate a list of users from the database or from any other source.

Generate & Download CSV File

Finally, below is a Spring MVC controller class that 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 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 browser. It also sets the attachment file name to users.csv
  • Use response writer (response.writer() returns an object of type PrintWriter) to build an instance of StatefulBeanToCsv.
  • Use write() method of StatefulBeanToCsv 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 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 Spring Boot application is started, open http://localhost:8080/export-users link in your favorite browser to generate and download users.csv file. Here is 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 important thing to note is the order of the columns in CSV file. OpenCSV sorts the column names in ascending order before writing into CSV file.

OpenCSV Columns Ordering

There is no built-in functionality in OpenCSV that allows to write bean to CSV with custom column names and ordering. However, using @CsvBindByPosition annotation, you can control the column positions in 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;

	//contructor, 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 OpenCSV library to generate and download a CSV file in Spring Boot. If you are not comfortable with using 3rd-party library, you can write your own CSV writer. Writing a CSV file is quite similar to writing a text file with few exceptions.

If you have any question or feedback, please feel free to send me a tweet.

Happy learning Spring Boot 😍

✌️ Like this article? Follow @attacomsian on Twitter. You can also follow me on LinkedIn and DEV. β˜• Buy me a coffee (cost $3)


Need help to start a new Spring Boot or MEAN stack project? I am available for contract work. Hire me to accomplish your business goals with engineering and design. Let’s talk about your project: hi@attacomsian.com.