Downloading a file from spring controllers

前端 未结 14 889
渐次进展
渐次进展 2020-11-22 01:06

I have a requirement where I need to download a PDF from the website. The PDF needs to be generated within the code, which I thought would be a combination of freemarker and

相关标签:
14条回答
  • 2020-11-22 01:30

    The following solution work for me

        @RequestMapping(value="/download")
        public void getLogFile(HttpSession session,HttpServletResponse response) throws Exception {
            try {
    
                String fileName="archivo demo.pdf";
                String filePathToBeServed = "C:\\software\\Tomcat 7.0\\tmpFiles\\";
                File fileToDownload = new File(filePathToBeServed+fileName);
    
                InputStream inputStream = new FileInputStream(fileToDownload);
                response.setContentType("application/force-download");
                response.setHeader("Content-Disposition", "attachment; filename="+fileName); 
                IOUtils.copy(inputStream, response.getOutputStream());
                response.flushBuffer();
                inputStream.close();
            } catch (Exception exception){
                System.out.println(exception.getMessage());
            }
    
        }
    
    0 讨论(0)
  • 2020-11-22 01:31

    With Spring 3.0 you can use the HttpEntity return object. If you use this, then your controller does not need a HttpServletResponse object, and therefore it is easier to test. Except this, this answer is relative equals to the one of Infeligo.

    If the return value of your pdf framework is an byte array (read the second part of my answer for other return values) :

    @RequestMapping(value = "/files/{fileName}", method = RequestMethod.GET)
    public HttpEntity<byte[]> createPdf(
                     @PathVariable("fileName") String fileName) throws IOException {
    
        byte[] documentBody = this.pdfFramework.createPdf(filename);
    
        HttpHeaders header = new HttpHeaders();
        header.setContentType(MediaType.APPLICATION_PDF);
        header.set(HttpHeaders.CONTENT_DISPOSITION,
                       "attachment; filename=" + fileName.replace(" ", "_"));
        header.setContentLength(documentBody.length);
    
        return new HttpEntity<byte[]>(documentBody, header);
    }
    

    If the return type of your PDF Framework (documentBbody) is not already a byte array (and also no ByteArrayInputStream) then it would been wise NOT to make it a byte array first. Instead it is better to use:

    • InputStreamResource,
    • PathResource (since Spring 4.0) or
    • FileSystemResource,

    example with FileSystemResource:

    @RequestMapping(value = "/files/{fileName}", method = RequestMethod.GET)
    public HttpEntity<byte[]> createPdf(
                     @PathVariable("fileName") String fileName) throws IOException {
    
        File document = this.pdfFramework.createPdf(filename);
    
        HttpHeaders header = new HttpHeaders();
        header.setContentType(MediaType.APPLICATION_PDF);
        header.set(HttpHeaders.CONTENT_DISPOSITION,
                       "attachment; filename=" + fileName.replace(" ", "_"));
        header.setContentLength(document.length());
    
        return new HttpEntity<byte[]>(new FileSystemResource(document),
                                      header);
    }
    
    0 讨论(0)
  • 2020-11-22 01:31

    If you:

    • Don't want to load the whole file into a byte[] before sending to the response;
    • Want/need to send/download it via InputStream;
    • Want to have full control of the Mime Type and file name sent;
    • Have other @ControllerAdvice picking up exceptions for you (or not).

    The code below is what you need:

    @RequestMapping(value = "/stuff/{stuffId}", method = RequestMethod.GET)
    public ResponseEntity<FileSystemResource> downloadStuff(@PathVariable int stuffId)
                                                                          throws IOException {
        String fullPath = stuffService.figureOutFileNameFor(stuffId);
        File file = new File(fullPath);
        long fileLength = file.length(); // this is ok, but see note below
    
        HttpHeaders respHeaders = new HttpHeaders();
        respHeaders.setContentType("application/pdf");
        respHeaders.setContentLength(fileLength);
        respHeaders.setContentDispositionFormData("attachment", "fileNameIwant.pdf");
    
        return new ResponseEntity<FileSystemResource>(
            new FileSystemResource(file), respHeaders, HttpStatus.OK
        );
    }
    

    About the file length part: File#length() should be good enough in the general case, but I thought I'd make this observation because it does can be slow, in which case you should have it stored previously (e.g. in the DB). Cases it can be slow include: if the file is large, specially if the file is in a remote system or something more elaborated like that - a database, maybe.



    InputStreamResource

    If your resource is not a file, e.g. you pick the data up from the DB, you should use InputStreamResource. Example:

        InputStreamResource isr = new InputStreamResource(new FileInputStream(file));
        return new ResponseEntity<InputStreamResource>(isr, respHeaders, HttpStatus.OK);
    
    0 讨论(0)
  • 2020-11-22 01:32

    I was able to stream line this by using the built in support in Spring with it's ResourceHttpMessageConverter. This will set the content-length and content-type if it can determine the mime-type

    @RequestMapping(value = "/files/{file_name}", method = RequestMethod.GET)
    @ResponseBody
    public FileSystemResource getFile(@PathVariable("file_name") String fileName) {
        return new FileSystemResource(myService.getFileFor(fileName)); 
    }
    
    0 讨论(0)
  • 2020-11-22 01:35

    This code is working fine to download a file automatically from spring controller on clicking a link on jsp.

    @RequestMapping(value="/downloadLogFile")
    public void getLogFile(HttpSession session,HttpServletResponse response) throws Exception {
        try {
            String filePathToBeServed = //complete file name with path;
            File fileToDownload = new File(filePathToBeServed);
            InputStream inputStream = new FileInputStream(fileToDownload);
            response.setContentType("application/force-download");
            response.setHeader("Content-Disposition", "attachment; filename="+fileName+".txt"); 
            IOUtils.copy(inputStream, response.getOutputStream());
            response.flushBuffer();
            inputStream.close();
        } catch (Exception e){
            LOGGER.debug("Request could not be completed at this moment. Please try again.");
            e.printStackTrace();
        }
    
    }
    
    0 讨论(0)
  • 2020-11-22 01:36

    You should be able to write the file on the response directly. Something like

    response.setContentType("application/pdf");      
    response.setHeader("Content-Disposition", "attachment; filename=\"somefile.pdf\""); 
    

    and then write the file as a binary stream on response.getOutputStream(). Remember to do response.flush() at the end and that should do it.

    0 讨论(0)
提交回复
热议问题