通过Spring MVC使用ajax()POST请求下载文件

der*_*xer 11 javascript jquery spring-mvc

我尝试下载文件.该操作由ajax()发布请求触发.请求以json格式将数据发送到控制器.控制器生成文件(字节)并将其发回.

java脚本:

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")
        } 
    });
}  
Run Code Online (Sandbox Code Playgroud)

控制器:

@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();
}
Run Code Online (Sandbox Code Playgroud)

问题:
*浏览器应该打开一个下载框,但它不会发生
*响应是在错误中处理的:ajax函数的一部分(但是http状态是OK)

那么我错了什么或者这样做的正确方法是什么?

Eug*_*nov 15

只需发送一个文件的URL作为响应,然后在您的success回调中"访问"它.

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");
        } 
    });
}
Run Code Online (Sandbox Code Playgroud)

data.fileUrl 应该由服务器设置响应,以说明客户端在哪里获取文件.

所以你的服务器会发送一个像JSON一样的响应

{
    "fileUrl": "http://mysite.com/files/0123456789"
}
Run Code Online (Sandbox Code Playgroud)


der*_*xer 7

@ will824正如你问的那样,我会发布自己的解决方案.

我在控制器中使用了一种解决方法,并将文件临时保存在文件系统(/ tmp)中.我分两步拆分了这个功能.创建和下载.这不是很好但对我来说足够好.

Controller(创建文件,将保存在服务器文件系统中):

@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;

}
Run Code Online (Sandbox Code Playgroud)

控制器(下载文件):

@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();
}
Run Code Online (Sandbox Code Playgroud)

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
        }
    });
}
Run Code Online (Sandbox Code Playgroud)


小智 5

如果要下载文件而不更改URL,则可以以form.submit() 编程方式调用而不是使用AJAX。

JavaScript:

function downloadFileUsingForm(url) { 
    var form = document.createElement("form");
    form.method = "post";
    form.action = url;
    document.body.appendChild(form);
    form.submit();
    document.body.removeChild(form);
}
downloadFileUsingForm("/YourController/DownloadFile");
Run Code Online (Sandbox Code Playgroud)

控制器:

[HttpPost]
public ActionResult DownloadFile()
{
    string content = "Some Values";
    byte[] bytes = System.Text.UTF8Encoding.UTF8.GetBytes(content);
    return File(bytes, System.Net.Mime.MediaTypeNames.Application.Octet, "file.txt");
}
Run Code Online (Sandbox Code Playgroud)