0

I'm trying to implement an ajax download. This is my code for the ajax request:

$('#download').click(function(){
                    $.ajax({  
                        url: '${downloadPath}',  
                        type: 'GET',  
                        data: {${_csrf.parameterName}:'${_csrf.token}'},  
                        success: function (res) {  
                        }
                    });
                });

And this is my controller's method:

    @Secured("IS_AUTHENTICATED")
    @RequestMapping(value="download/{id}", method=RequestMethod.GET, produces="application/pdf")
    @ResponseBody
    public void download(@PathVariable(value="id") final Long id, HttpServletResponse response) throws IOException {

        CheckList checkList = checkListService.findById(id);
//      byte[] byteItem  = checkListService.getFileByIdDocument(id);

        File f = new File(VariabiliGlobali.PATH_CHECKLIST+checkList.getPratica().getId()+"/"+id);
        ServletOutputStream out = response.getOutputStream();

        response.setContentType("application/pdf");
        response.setContentLength((int)f.length());
        response.setHeader("Content-Disposition", "attachment; filename=\"" + f.getName() + "\"");

        FileInputStream in = new FileInputStream(f);
        byte[] buffer = new byte[4096];

        int length;
        while( (length = in.read(buffer) ) > 0) {
            out.write(buffer, 0, length);
        }
        in.close();
        out.flush();   
    }

I can see the pdf inside the response:

enter image description here

But my browser (Chrome) doens't do anything.

Where am I wrong? How can I dowload it?

Teo
  • 3,143
  • 2
  • 29
  • 59
  • Remove the `@ResponseBody` from the controller – StanislavL Jul 07 '17 at 13:48
  • @StanislavL also if I remove `@ResponseBody` it doesn't work – Teo Jul 07 '17 at 13:53
  • Why do you need AJAX at all? `window.location = '${downloadPath}';` should be enough. In opposite case AJAX suppose processing the response (see https://stackoverflow.com/questions/20830309/download-file-using-an-ajax-request) – StanislavL Jul 07 '17 at 13:56

2 Answers2

0

You don't need ajax and you are using as content type application/octet-stream as we can see in your code here:

 response.setContentType("application/octet-stream");

If you want to display the pdf inside the browser (if the browser has the proper plugin to read pdf) you should use:

  • the right pdf content type
  • set the proper header

In my code i did the following:

response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "inline; filename=pdfFileName.pdf;");

In any case I'd suggest to yuo to use the "spring" way like this:

    @Secured("IS_AUTHENTICATED")
    @RequestMapping(value="download/{id}", method=RequestMethod.GET)
        public ResponseEntity<InputStreamResource> download(@PathVariable(value="id") final Long id) throws IOException {
    HttpHeaders respHeaders = new HttpHeaders();

                    MediaType mediaType = new MediaType("application","pdf");
                    respHeaders.setContentType(mediaType);
                    respHeaders.setContentDispositionFormData("inline", "pdfFileName.pdf");
//Here you have to take the InputStream of the file you want to download
                    InputStreamResource isr = new InputStreamResource(new FileInputStream(file));
                    return new ResponseEntity<InputStreamResource>(isr, respHeaders, HttpStatus.OK);
    }

I hope it's useful

Angelo

Angelo Immediata
  • 6,635
  • 4
  • 33
  • 65
  • If I use your I otain this error: `No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer` and then I can't do `InputStreamResource isr = new InputStreamResource(new FileInputStream(file))`; but `InputStreamResource isr = new InputStreamResource(); isr.setInputStream(new FileInputStream(new File(path))` – Teo Jul 07 '17 at 14:13
  • that's stange... maybe it's some spring configuration issue. In any case if you use the first approach (the one you used) and add what I suggested (the right content type) and you put in the browser the URL (without using any kind of Ajax call) doas it work? – Angelo Immediata Jul 07 '17 at 15:04
  • If I use a submit to reach the controller and download it, yes it works – Teo Jul 07 '17 at 15:45
  • so yuo can assume that: it's sure you don't need AJAX and that you need to investigate on spring configuration in order to make work the sample I wrote... but you can always use your controller – Angelo Immediata Jul 07 '17 at 15:50
0

Set your content type in header. So browsers handles the pdf.

headers.setContentType(MediaType.parseMediaType("application/pdf"));

Below is the sample code.

@Secured("IS_AUTHENTICATED")
@RequestMapping(value="download/{id}", method=RequestMethod.GET, produces="application/pdf")
public ResponseEntity<?> download(@PathVariable(value="id") final Long id, HttpServletResponse response) throws IOException {       
    List<SampleDto> reportData = new ArrayList<SampleDto>();

    HttpHeaders headers = new HttpHeaders();

    if (null == reportData || reportData.size() == 0) {
        return new ResponseEntity<byte[]>(null, headers, HttpStatus.NO_CONTENT);
    }

    byte[] contents = writePdfContentToBytes();//Here you should your code to get content in bytes.

    headers.setContentType(MediaType.parseMediaType("application/pdf"));
    headers.setContentDispositionFormData("inline", "Report.pdf");
    return new ResponseEntity<byte[]>(contents, headers, HttpStatus.OK);
}
Sudhakar
  • 3,104
  • 2
  • 27
  • 36
  • I implemented also yours code, but it doesn't work.. I have the response with pdf inside, but I can't see it or download it.. – Teo Jul 07 '17 at 14:43
  • Can add your UI code like below. $('#download').click(function(){ $.ajax({ url: '${downloadPath}', type: 'GET', data: {${_csrf.parameterName}:'${_csrf.token}'}, success: function (res) { var win = window.open('', '_blank'); win.location = url; win.focus(); } }); }); – Sudhakar Jul 07 '17 at 14:52