Saturday, April 18, 2020

Spring MVC Download File Controller Example

In Spring MVC application, to download a resource such as a file to the browser, you need to do the following in your controller.
  1. Use the void return type for your request-handling method and add HttpServletResponse as an argument to the method.
  2. Set the response’s content type to the file’s content type. If you do not know what the content type is or want the browser to always display the Save As dialog, set it to APPLICATION/OCTET-STREAM (NOT case sensitive).
  3. Add an HTTP response header named Content-Disposition and give it the value attachment; filename=fileName, where fileName is the default file name that should appear in the File Download dialog box.

1. Sping MVC File Download Controller

Let’s look at an example implementation for file download controller.
@Controller
@RequestMapping("/download")
public class FileDownloadController
{
    @RequestMapping("/pdf/{fileName:.+}")
    public void downloadPDFResource( HttpServletRequest request,
                                     HttpServletResponse response,
                                     @PathVariable("fileName") String fileName)
    {
        //If user is not authorized - he should be thrown out from here itself
         
        //Authorized user will download the file
        String dataDirectory = request.getServletContext().getRealPath("/WEB-INF/downloads/pdf/");
        Path file = Paths.get(dataDirectory, fileName);
        if (Files.exists(file))
        {
            response.setContentType("application/pdf");
            response.addHeader("Content-Disposition", "attachment; filename="+fileName);
            try
            {
                Files.copy(file, response.getOutputStream());
                response.getOutputStream().flush();
            }
            catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
}
If you want to enable downloads for only authorized users then check the user’s logged in status first in the method, and then allow download otherwise redirect him to login screen.
Now if you hit the application URL : http://localhost:8080/springmvcexample/download/pdf/sample.pdf, you will be able to get the Save As dialog box in your browser like below:
File download window
File download window
The file is placed inside folder “/WEB-INF/downloads/pdf”. You are free to change the path – make sure you change the controller code as well.
File download project structure
File download project structure

2. Prevent Cross-Referencing of File Downloads

Many times, other websites may cross reference your files in their websites as direct links. You may not want to allow it. To disallow all download requests, coming from other domains, you can check if the referer header contains your domain name.
Our modified FileDownloadController will send files to the browser, only if the referer header is not null. This will prevent the images from being downloaded directly by typing their URLs in the browser or request coming from other domains.
@Controller
@RequestMapping("/download")
public class FileDownloadController
{
    @RequestMapping("/pdf/{fileName:.+}")
    public void downloadPDFResource( HttpServletRequest request,
                                     HttpServletResponse response,
                                     @PathVariable("fileName") String fileName,
                                     @RequestHeader String referer)
    {
        //Check the renderer
        if(referer != null && !referer.isEmpty()) {
            //do nothing
            //or send error
        }
        //If user is not authorized - he should be thrown out from here itself
         
        //Authorized user will download the file
        String dataDirectory = request.getServletContext().getRealPath("/WEB-INF/downloads/pdf/");
        Path file = Paths.get(dataDirectory, fileName);
        if (Files.exists(file))
        {
            response.setContentType("application/pdf");
            response.addHeader("Content-Disposition", "attachment; filename="+fileName);
            try
            {
                Files.copy(file, response.getOutputStream());
                response.getOutputStream().flush();
            }
            catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
}
Now if you try to hit the URL from browser directly, you will get this error:
java.lang.IllegalStateException: Missing header 'referer' of type [java.lang.String]
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.raiseMissingHeaderException(HandlerMethodInvoker.java:797)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveRequestHeader(HandlerMethodInvoker.java:566)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:355)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:172)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:446)
Drop me your questions in comments section.

No comments:

Post a Comment

How to DROP SEQUENCE in Oracle?

  Oracle  DROP SEQUENCE   overview The  DROP SEQUENCE  the statement allows you to remove a sequence from the database. Here is the basic sy...