3

I am currently working with jQuery and Spring Rest. jQuery is used to upload and download files to the Server. The upload process is working fine but I have little problem with downloading the files. So the scenario is, in the view, the user will select the n numbers of files to download and clicks the download button. Once the user clicks that button, the files will be downloaded. I do not want to open a new new tab for each file download. I would like to download on the same window without refreshing the current view. I looked into this but didn't help me much. Is there any way, I can achieve this?

Community
  • 1
  • 1
Rana_S
  • 1,520
  • 2
  • 23
  • 39

2 Answers2

2

Here is my solution to download the file:

Spring Controller method:

@RequestMapping(value = "/download", method = RequestMethod.GET)
public void retrieveDocument(@RequestParam("id") String id, HttpServletResponse response) throws IOException {
    InputStream in = fileService.getFileStream(); // My service to get the stream.
    response.setContentType(MediaType.APPLICATION_OCTET_STREAM);
    response.setHeader("Content-Transfer-Encoding", "binary");
    response.setHeader("Content-Disposition", "attachment; filename=" + filename);
    try {
        IOUtils.copy(inputStream, response.getOuputStream()); //Apache commons IO.
        inputStream.close();
        response.flushBuffer();
        response.setStatus(HttpServletResponse.SC_OK);
    } catch (Exception e) {
        //log error.
    }

}

On client side function:

function download(id) {
    var id = $('#file').attr('id')
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'url here' + id, true);
    xhr.responseType = 'arraybuffer';
    xhr.onload = function() {
        if(this.status == '200') {
           var filename = '';
           //get the filename from the header.
           var disposition = xhr.getResponseHeader('Content-Disposition');
           if (disposition && disposition.indexOf('attachment') !== -1) {
               var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
               var matches = filenameRegex.exec(disposition);
               if (matches !== null && matches[1])
                   filename = matches[1].replace(/['"]/g, '');
           }
           var type = xhr.getResponseHeader('Content-Type');
           var blob = new Blob([this.response],  {type: type});
           //workaround for IE
           if(typeof window.navigator.msSaveBlob != 'undefined') {
               window.navigator.msSaveBlob(blob, filename);
           }
           else {
               var URL = window.URL || window.webkitURL;
               var download_URL = URL.createObjectURL(blob);
               if(filename) {
                   var a_link = document.createElement('a');
                   if(typeof a_link.download == 'undefined') {
                       window.location = download_URL;
                   }else {
                       a_link.href = download_URL;
                       a_link.download = filename;
                       document.body.appendChild(a_link);
                       a_link.click();
                   }
               }else {
                   window.location = download_URL;
               }
               setTimeout(function() {
                   URL.revokeObjectURL(download_URL);
               }, 10000);
           }
        }else {
            alert('error')';//do something...
        }
    }; 
    xhr.setRequestHeader('Content-type', 'application/*');
    xhr.send();
}
user1814879
  • 984
  • 6
  • 23
  • 49
Rana_S
  • 1,520
  • 2
  • 23
  • 39
1

I answered something similar a few minutes ago: sending file from response to user, Spring REST + jQuery


I recommend you to use this JS plugin https://github.com/johnculviner/jquery.fileDownload to download the file instead using $.ajax directly. You can find all the official documentation there.

Also, in your controller, you have to take your HttpServletResponse and write the byte[] in the outputstream, and you have to put a cookie in the response to advise the JS plugin (because it needs it)

For example:

@RequestMapping(value = "/download", method = RequestMethod.GET)
    public void getFilesInZIP(@RequestParam("filenames[]") String[] filenames, HttpServletResponse httpServletResponse){
        byte[] file = service.packFilesToZIPArchiveAndReturnAsByteArray(filenames);

        Cookie cookie = new Cookie("fileDownload", "true");
        cookie.setPath("/");

        httpServletResponse.addCookie(cookie);
        httpServletResponse.setContentType("application/zip");
        httpServletResponse.setHeader("Content-Disposition", "attachment;filename=files.zip");
        httpServletResponse.getOutputStream().write(file);

    }
Community
  • 1
  • 1
Roman
  • 313
  • 3
  • 9
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/low-quality-posts/10266851) – Nate Barbettini Nov 19 '15 at 20:24
  • It's the same problem that another had in other thread. I prefer to give him the link with my answer instead of making Copy+Paste – Roman Nov 19 '15 at 20:55
  • Understood. We typically try to avoid link-only answers here on StackOverflow, though. (Here's some [relevant discussion](http://meta.stackexchange.com/questions/8231/are-answers-that-just-contain-links-elsewhere-really-good-answers).) Links are perfectly fine in a comment, or you can try to distill the key points of the answer along with the link. – Nate Barbettini Nov 19 '15 at 21:20