Downloading Files in Spring Boot

  • Last updated Apr 25, 2024

In this tutorial, we will explore how to download files in a Spring Boot application. File downloads are a common requirement in web applications, and Spring Boot provides convenient features to handle this scenario efficiently.

Here's an example code that demonstrates the usage of the StreamingResponseBody interface as the response type for an API. This interface allows direct writing of data to the response OutputStream, making it suitable for file downloads:

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import jakarta.servlet.http.HttpServletResponse;

@RestController
@RequestMapping(value = "/files")
public class FileDownloadController {

  @GetMapping(path = "/downloads/{fileId}")
  public StreamingResponseBody downloadFile(HttpServletResponse response, @PathVariable(name = "fileId") String fileId) {

    // file path is usually store in a database and is retrieved by id
    String fileLocation = "C:/Documents/Videos/video_123.mp4";

    File file = new File(fileLocation);

    response.setContentLength((int) file.length());
    response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
    int BUFFER_SIZE = 1024;

    return outputStream -> {
	int bytesRead;
	byte[] buffer = new byte[BUFFER_SIZE];

	// convert the file to InputStream
	InputStream inputStream = new FileInputStream(file);
	while ((bytesRead = inputStream.read(buffer)) != -1) {
	   outputStream.write(buffer, 0, bytesRead);
	}

	if (inputStream != null) {
	   inputStream.close();
	}
     };
  }

}

Here's an explanation of the above code:

  1. The class is named FileDownloadController, annotated with @RestController to indicate that it is a controller class handling HTTP requests and producing responses.
  2. The base URL mapping for all endpoints in this controller is set to "/files" using @RequestMapping(value = "/files").
  3. The downloadFile method is defined and annotated with @GetMapping to handle HTTP GET requests to "/downloads/{fileId}". The fileId path variable represents the unique identifier of the file to be downloaded.
  4. Inside the method, the file location should be typically retrieved from a database based on the fileId. In this example, it is hardcoded to "C:/Documents/Videos/video_123.mp4".
  5. A File object is created using the file location.
  6. The response headers are configured. The Content-Length header is set to the length of the file, and the Content-Disposition header is set to "attachment" to indicate that the file should be downloaded rather than displayed in the browser. The filename is set to the name of the file being downloaded.
  7. The BUFFER_SIZE variable is defined to determine the size of the buffer used for reading and writing the file content.
  8. The method returns a StreamingResponseBody, which is an interface representing the response body that can be streamed directly to the client.
  9. Inside the StreamingResponseBody implementation, an anonymous lambda function is used to write the file content to the response OutputStream. The file is converted to an InputStream, and data is read from the input stream in chunks and written to the output stream using the buffer. This allows efficient streaming of the file content to the client.
  10. After the streaming is complete, the InputStream is closed.

In summary, this code sets up a file download endpoint in a Spring Boot application. When a GET request is made to "/files/downloads/{fileId}", the corresponding file is retrieved and streamed to the client as a response, allowing the user to download the file.