File Download Example Using Spring REST Controller

File Download

File download example using Spring REST Controller will show you how to download a file from any client (browser or any client) and Spring REST service is used as a server side technology for downloading the file. The file may be any type, i.e., such as excel, text, word, pdf etc. Here I will create Spring Boot application as it reduces our most of the efforts in project configurations.

You might have seen how to download a file using REST web service using Jersey API in my other tutorial but here I will see how to download a file using Spring REST Controller.

Related Posts:

For various reasons, such as, reporting or any other purpose you may need to download file and in our today’s application I am using mostly REST services to make the application loosely coupled, it is sometimes required to download the file using REST service.

Prerequisites

Java 8/12/19, Gradle 6.1.1 – 6.7.1, maven 3.6.3/3.8.5, Spring Boot 2.2.5 – 2.4.3/3.1.5, MySQL 8.0.17 – 8.0.22/8.1.0

Project Setup

As a prerequisite I have to first setup the project environment so that I would be able to write the required code for downloading file into server and save the file anywhere on a physical location in your system. Create below build.gradle script to add the required project dependencies. I have also specified the JDK version I will be using for our application. File download example using Spring REST Controller does not many dependencies and you need to add only spring boot started web for downloading a file.

For spring boot 3 use the following pom.xml file:

<?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.roytuts</groupId>
	<artifactId>spring-rest-file-download</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>19</maven.compiler.source>
		<maven.compiler.target>19</maven.compiler.target>
	</properties>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.1.5</version>
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		
		<dependency>
			<groupId>com.mysql</groupId>
			<artifactId>mysql-connector-j</artifactId>			
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

For spring boot 2 use the following build.gradle or pom.xml file below:

buildscript {
	ext {
		springBootVersion = '2.2.5.RELEASE' to 2.4.3
	}
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

plugins {
    id 'java-library'
    id 'org.springframework.boot' version "${springBootVersion}"
}

sourceCompatibility = 12
targetCompatibility = 12

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
    implementation("org.springframework.boot:spring-boot-starter-data-jpa:${springBootVersion}")
    implementation('mysql:mysql-connector-java:8.0.17') //8.0.22
	//required only if jdk 9 or higher version is used
    runtimeOnly('javax.xml.bind:jaxb-api:2.4.0-b180830.0359')
}

If you are creating maven based project then you can use below pom.xml file:

<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.roytuts</groupId>
	<artifactId>spring-rest-file-download</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.5.RELEASE to 2.4.3</version>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                <maven.compiler.source>12</maven.compiler.source>
		<maven.compiler.target>12</maven.compiler.target>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		
		<!--required only if jdk 9 or higher version is used-->
		<dependency>
			<groupId>javax.xml.bind</groupId>
			<artifactId>jaxb-api</artifactId>
		</dependency>
	</dependencies>

    <build>
        <plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
			</plugin>
		</plugins>
	</build>
</project>

Application Config

I am creating below application.properties file under classpath directory src/main/resources to configure the MySQL database settings. I do not need to create any datasource explicitly as I am using the standard naming conventions for database configurations and Spring Boot will automatically create one for us.

spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/roytuts
spring.datasource.username=root
spring.datasource.password=root

Entity Class

Create below entity class that maps to database table. Our entity class has only three fields employee id, employee first name and employee last name. I am creating entity class because I want to create a file from our database record and finally download the file using Spring REST service. Here I will build a JSON file from database employee table and download that JSON file. You can build any type of file, such as excel file, csv file etc. to fulfil your project’s requirement.

@Entity
@Table(name = "employee")
public class Employee implements Serializable {

	private static final long serialVersionUID = 1L;

	@Id
	@Column(name = "id")
	private Integer empId;

	@Column(name = "first_name")
	private String empFirstName;

	@Column(name = "last_name")
	private String empLastName;

	//getters and setters

}

Spring Data JPA Repository

Here in the file download example using Spring REST Controller, I am using Spring Data JPA in order to query the database and fetch data from database table. So create below Spring Data JPA Repository which provides most of our built-in methods to query database for fetching data.

public interface EmployeeRepository extends JpaRepository<Employee, Integer> {

}

Spring Service

Create below service class which will fetch data from Spring Data JPA Repository and send to Spring REST Controller that will generate the file for download. I fetch all employees from the database using the below service layer code. I annotate the service layer class using @Service. I create service layer class to process our business logic to avoid any tight coupling between the layers.

@Service
public class EmployeeService {

	@Resource
	private EmployeeRepository employeeRepository;

	public List<Employee> getEmployees() {
		return employeeRepository.findAll();
	}

}

Spring REST Controller

This is where I write code for file download example using Spring REST Controller. The below Spring REST Controller class to receive the downloaded file from client.

I have the http method GET request and the file can be downloaded from browser or any REST client or UI.

I use the data type as array of byte stream in the response to download the file. File may be downloaded from a selected location using the server side code or you may generated a report file from database and download the report file using the Spring REST Controller.

Notice how I attach the file in the http header response so that file will be forced to download and give a pop-up for saving it. You must specify few things, such as, content length, content type, attachment with file name in order to download the file forcefully.

@RestController
public class FileDownloadRestController {

	@Autowired
	private EmployeeService employeeService;

	@GetMapping("/download")
	public ResponseEntity<byte[]> downloadErrorData() throws Exception {
		List<Employee> employees = employeeService.getEmployees();
		ObjectMapper objectMapper = new ObjectMapper();
		String json = objectMapper.writeValueAsString(employees);
		byte[] isr = json.getBytes();
		String fileName = "employees.json";
		HttpHeaders respHeaders = new HttpHeaders();
		respHeaders.setContentLength(isr.length);
		respHeaders.setContentType(new MediaType("text", "json"));
		respHeaders.setCacheControl("must-revalidate, post-check=0, pre-check=0");
		respHeaders.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName);
		return new ResponseEntity<byte[]>(isr, respHeaders, HttpStatus.OK);
	}

}

You can also have a file in the server side in any location and you can download the file directly without having to fetch data from MySQL database server. For example let’s say you have a sample example.json file in your server location and you want to download the file. Then you do not need application.properties, Entity, JpaRepository and Service classes. You can use the following code snippets to download your example.json file.

@GetMapping("/download")
public ResponseEntity<byte[]> downloadErrorData() throws Exception {
	Path path = Paths.get("C:/spring-rest-file-download/example.json");
	byte[] isr = Files.readAllBytes(path);
	String fileName = "example.json";

	HttpHeaders respHeaders = new HttpHeaders();
	respHeaders.setContentLength(isr.length);
	respHeaders.setContentType(new MediaType("text", "json"));
	respHeaders.setCacheControl("must-revalidate, post-check=0, pre-check=0");
	respHeaders.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName);

	return new ResponseEntity<byte[]>(isr, respHeaders, HttpStatus.OK);
}

Main Class

Now major coding part is done and it’s time to deploy the application into embedded tomcat server. Create below Spring Boot main class to deploy the application into Tomcat server.

@EntityScan(basePackages = "com.roytuts.entity")
@SpringBootApplication(scanBasePackages = "com.roytuts")
@EnableJpaRepositories(basePackages = "com.roytuts.repository")
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

}

MySQL Table

I will create employee table under roytuts database into MySQL server.

CREATE TABLE IF NOT EXISTS `employee` (
  `id` int NOT NULL DEFAULT '0',
  `first_name` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
  `last_name` varchar(15) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO `employee` (`id`, `first_name`, `last_name`) VALUES
	(1003349, 'Liton', 'Sarkar'),
	(1003350, 'Debabrata', 'Poddar'),
	(1003351, 'Abhisekh', 'Paul'),
	(1003352, 'Sumit', 'Ghosh'),
	(1003353, 'Manoj', 'Kumar'),
	(1003354, 'Sreeja', 'Chowdhury');

Testing the File Download Application

Now it’s time to test the application for file download example using Spring REST Controller. You may also like to read my previous tutorial on file upload using Spring REST Controller.

When you hit the URL http://localhost:8080/download from browser or REST client then you would be able to receive the below JSON records in a file assuming your database employee table has the similar records.

[
	{"empId":"1003349","empFirstName":"Liton","empLastName":"Sarkar"},
	{"empId":"1003350","empFirstName":"Debabrata","empLastName":"Poddar"},
	{"empId":"1003351","empFirstName":"Abhisekh","empLastName":"Paul"},
	{"empId":"1003352","empFirstName":"Sumit","empLastName":"Ghosh"},
	{"empId":"1003353","empFirstName":"Manoj","empLastName":"Kumar"},
	{"empId":"1003354","empFirstName":"Sreeja","empLastName":"Chowdhury"}
]

The content of the example.json file is and can be downloaded from the Source Code section below:

{
    "quiz": {
        "sport": {
            "q1": {
                "question": "Which one is correct team name in NBA?",
                "options": [
                    "New York Bulls",
                    "Los Angeles Kings",
                    "Golden State Warriros",
                    "Huston Rocket"
                ],
                "answer": "Huston Rocket"
            }
        },
        "maths": {
            "q1": {
                "question": "5 + 7 = ?",
                "options": [
                    "10",
                    "11",
                    "12",
                    "13"
                ],
                "answer": "12"
            },
            "q2": {
                "question": "12 - 8 = ?",
                "options": [
                    "1",
                    "2",
                    "3",
                    "4"
                ],
                "answer": "4"
            }
        }
    }
}

That’s all about how to download file using Spring REST controller.

Source Code

Download

Leave a Reply

Your email address will not be published. Required fields are marked *