Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Download file with ajax() POST request via Spring MVC

I try to download a file. The action is triggered by ajax() POST request. The request sends data in JSON format to the controller. The controller generates the file (bytes) and sends it back.

JavaScript:

function getLicenseFile() {
    $.ajax({
        type: 'POST',
        url: '<%=request.getContextPath()%>/licenses/rest/downloadLicenseFile',
        dataType: 'json',
        contentType: 'application/json;charset=UTF-8',
        data: ko.mapping.toJSON(licenseModel),
        success: function (data) {
            console.log("in sucess")
        },
        error:function (xhr, ajaxOptions, thrownError){
            console.log("in error")
        } 
    });
}  

Controller:

@RequestMapping(value = "/licenses/rest/downloadLicenseFile", method = RequestMethod.POST)
@ResponseStatus(value=HttpStatus.OK)
@ResponseBody
public void createLicenseFile(@Valid @RequestBody License license, HttpServletResponse response) throws Exception {

    logger.debug("Contoller License in: "+ license);

    byte[] licensedata = licenseEncodeDefaultService.createLicenseFile(license);
    logger.debug("licenseData: " + new String(licensedata));

    response.setHeader("Content-Disposition", "attachment; filename=\"" + license.getCustomer() + ".license\"");
    response.getOutputStream().write(licensedata);
    response.flushBuffer();
}


Problem

  • The Browser should open a download box, but it does not happen
  • The response is handled in the error: section of ajax function (but the HTTP Status is OK)

So what do I do wrong or what is the proper way to do this?

like image 434
derlinuxer Avatar asked Nov 22 '12 19:11

derlinuxer


2 Answers

Just send a URL of file in response and then "visit" it in your success callback.

function getLicenseFile() {
    $.ajax({
        type: 'POST',
        url: '<%=request.getContextPath()%>/licenses/rest/downloadLicenseFile',
        dataType: 'json',
        contentType: 'application/json;charset=UTF-8',
        data: ko.mapping.toJSON(licenseModel),
        success: function (data) {
            window.open(data.fileUrl);
            // or window.location.href = data.fileUrl;
        },
        error:function (xhr, ajaxOptions, thrownError) {
            console.log("in error");
        } 
    });
}

data.fileUrl should be set in response by server to say client where to get the file.

So your server will send a response with JSON like

{
    "fileUrl": "http://mysite.com/files/0123456789"
}
like image 143
Eugene Naydenov Avatar answered Oct 27 '22 02:10

Eugene Naydenov


@will824 As you ask I'll post my own solution.

I used a workaround in controller and save the file temporarily in the files ystem (/tmp). I split up the function in 2 steps. Creating and downloading. This is not very nice but good enough for me.

Controller (creates a file, will be saved on the server file system):

@RequestMapping(value = "/licenses/rest", method = RequestMethod.PUT)
@ResponseStatus(value=HttpStatus.OK)
@ResponseBody
public String createLicenseFile(@Valid @RequestBody License license) throws Exception {

    // create encrypted license file and send the name back to view
    String fileName =  licenseEncodeDefaultService.createLicenseFile(license);
    return fileName;

}

Controller (downloads a file):

@RequestMapping(value = "/licenses/downloadFile/{file}", method = RequestMethod.GET)
public void downloadLicenseFile(@PathVariable("file") String file, HttpServletResponse response) throws Exception {

    // create full filename and get input stream
    File licenseFile = new File ("/tmp/" + file);
    InputStream is = new FileInputStream(licenseFile);

    // set file as attached data and copy file data to response output stream
    response.setHeader("Content-Disposition", "attachment; filename=\"" + file + ".license\"");
    FileCopyUtils.copy(is, response.getOutputStream());

    // delete file on server file system
    licenseFile.delete();

    // close stream and return to view
    response.flushBuffer();
}

JavaScript:

function getLicenseFile() {
    //console.log(ko.mapping.toJSON(licenseModel));
    $.ajax({
        type : 'PUT',
        url : '${pageContext.request.contextPath}/licenses/rest',
        dataType : 'text',
        contentType : 'application/json;charset=UTF-8',
        data : ko.mapping.toJSON(licenseModel),
        success : function(data) {
            window.location.href = '${pageContext.request.contextPath}/licenses/downloadFile/'
                    + data;
        },
        error : function(xhr, ajaxOptions, thrownError) {
            // error handling
        }
    });
}
like image 20
derlinuxer Avatar answered Oct 27 '22 01:10

derlinuxer