Spring MVC Download File Examples

In this tutorial we show you how to use Spring MVC to download a file. You can either download a file as an attachment or directly view the file inside the browser. To show the file directly in the browser, the browser needs to support the specified file type. We demonstrate the file download using multiple methods: via HttpServletResponse, via HttpEntity and via FileSystemResource. We also show you how to handle exceptions while downloading.

Spring MVC Download File

The DownloadController below is used to download a file. There are three ways you can download a file via Spring MVC. Later in this example, we’ll take a look at them individually. Notice that when we get the file, we check if the file exists. If the file does not exist, we throw a FileNotFoundException before we set any headers on the response. This is important, otherwise the exception handler will not properly resolve the exception.

package com.memorynotfound.controller;

import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import java.io.*;

@Controller
@RequestMapping("/download")
public class DownloadController {

    private static final String FILE_PATH = "/tmp/example.pdf";
    private static final String APPLICATION_PDF = "application/pdf";

    @RequestMapping(value = "/a", method = RequestMethod.GET, produces = APPLICATION_PDF)
    public @ResponseBody void downloadA(HttpServletResponse response) throws IOException {
        File file = getFile();
        InputStream in = new FileInputStream(file);

        response.setContentType(APPLICATION_PDF);
        response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
        response.setHeader("Content-Length", String.valueOf(file.length()));
        FileCopyUtils.copy(in, response.getOutputStream());
    }

    @RequestMapping(value = "/b", method = RequestMethod.GET, produces = APPLICATION_PDF)
    public @ResponseBody HttpEntity<byte[]> downloadB() throws IOException {
        File file = getFile();
        byte[] document = FileCopyUtils.copyToByteArray(file);

        HttpHeaders header = new HttpHeaders();
        header.setContentType(new MediaType("application", "pdf"));
        header.set("Content-Disposition", "inline; filename=" + file.getName());
        header.setContentLength(document.length);

        return new HttpEntity<byte[]>(document, header);
    }

    @RequestMapping(value = "/c", method = RequestMethod.GET, produces = APPLICATION_PDF)
    public @ResponseBody Resource downloadC(HttpServletResponse response) throws FileNotFoundException {
        File file = getFile();
        response.setContentType(APPLICATION_PDF);
        response.setHeader("Content-Disposition", "inline; filename=" + file.getName());
        response.setHeader("Content-Length", String.valueOf(file.length()));
        return new FileSystemResource(file);
    }

    private File getFile() throws FileNotFoundException {
        File file = new File(FILE_PATH);
        if (!file.exists()){
            throw new FileNotFoundException("file with path: " + FILE_PATH + " was not found.");
        }
        return file;
    }

}

Download File via HttpServletResponse

We can use the HttpServletResponse to write a file directly to the ServletOutputStream using the FileCopyUtils. Note that the return type of this method is void. First, – in order that the browser understands which file is sent over the wire – we need to set the appropriate headers like: Content-Type, Content-Disposition and Content-Length. The Content-Disposition header instructs the browser which filename is used to download the file and whether the file needs to be downloaded as an attachment or displayed in the browser. Using the attachment like we did here, will directly download the file as an attachment.

@RequestMapping(value = "/a", method = RequestMethod.GET, produces = APPLICATION_PDF)
public @ResponseBody void downloadA(HttpServletResponse response) throws IOException {
    File file = getFile();
    InputStream in = new FileInputStream(file);
    response.setContentType(APPLICATION_PDF);
    response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
    response.setHeader("Content-Length", String.valueOf(file.length()));
    FileCopyUtils.copy(in, response.getOutputStream());
}

Download File via HttpEntity

We can also use the HttpEntity. This time we return a HttpEntity<byte[]>. We set the same headers like before using the HttpHeaders, but instead of attachment we use inline to instruct the browser to display the file directly in the browser – if the file type is supported.

@RequestMapping(value = "/b", method = RequestMethod.GET, produces = APPLICATION_PDF)
public @ResponseBody HttpEntity<byte[]> downloadB() throws IOException {
    File file = getFile();
    byte[] document = FileCopyUtils.copyToByteArray(file);
    HttpHeaders header = new HttpHeaders();
    header.setContentType(new MediaType("application", "pdf"));
    header.set("Content-Disposition", "inline; filename=" + file.getName());
    header.setContentLength(document.length);
    return new HttpEntity<byte[]>(document, header);
}

Download File via Resource

Instead of managing the InputStream we can also let Spring MVC handle the streams using the FileSystemResource. There are many implementations of the Resource class, couple of examples:

  • The ClassPathResource searches for a given file on the classpath, this could either be dynamically loaded on the classpath or resides as a file inside your project.
  • The UrlResource supports file resolution as a URL resource.
@RequestMapping(value = "/c", method = RequestMethod.GET, produces = APPLICATION_PDF)
public @ResponseBody Resource downloadC(HttpServletResponse response) throws FileNotFoundException {
    File file = getFile();
    response.setContentType(APPLICATION_PDF);
    response.setHeader("Content-Disposition", "inline; filename=" + file.getName());
    response.setHeader("Content-Length", String.valueOf(file.length()));
    return new FileSystemResource(file);
}

File Download Exception handling

Remember that after we retrieve the file, we inspect if the file exists. If the file does not exist, we throw a FileNotFoundException. This is not the only exception the code could throw. A IOException could also occur when the file is written to the OutputStream. We handle both exceptions using these exception handlers below. By annotating the class with @ControllerAdvice this class will be registered by spring as a global exception handler. The @ExceptionHandler annotation, in conjunction with the expected exception will handle those exceptions. Inside these handlers we re-trown the exception using the correct status code and the given error message.

package com.memorynotfound.exception;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import javax.servlet.http.HttpServletResponse;
import java.io.FileNotFoundException;
import java.io.IOException;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = FileNotFoundException.class)
    public void handle(FileNotFoundException ex, HttpServletResponse response) throws IOException {
        System.out.println("handling file not found exception");
        response.sendError(404, ex.getMessage());
    }

    @ExceptionHandler(value = IOException.class)
    public void handle(IOException ex, HttpServletResponse response) throws IOException {
        System.out.println("handling io exception");
        response.sendError(500, ex.getMessage());
    }
}

File Download View

We demonstrate this Spring MVC Download example using the following view. These links on the page will trigger each method individually and according to the Content-Disposition attribute, they will download the file as an attachment or directly display the file in the browser.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Spring MVC Download File Example</title>
</head>
<body>

    <h1>Spring MVC Download File Example</h1>

    <a href="<c:url value='/download/a'/>">Download file via servlet response.</a><br/>
    <a href="<c:url value='/download/b'/>">Download file via http entity.</a><br/>
    <a href="<c:url value='/download/c'/>">Download file via file system resource.</a><br/>

</body>
</html>

Demo

spring mvc download file example

Downloaded the file as an attachment.

spring mvc download file downloaded attachment

Directly display the file in the browser.

spring mvc download file downloaded inline

References

Download

You may also like...

  • Victor Herasme Perez

    Hi,

    thanks for this tutorial. I wonder where the function getFile() is defined. It is clear that you useit in order to get the file from somewhere in the system, but I just want to be sure I don’t miss anything. Regards,

    Victor