Javascript 通过 Spring MVC 使用 ajax() POST 请求下载文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13519058/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Download file with ajax() POST request via Spring MVC
提问by derlinuxer
I try to download a file. The action is triggered by ajax()POST request. The request sends datain JSON format to the controller. The controller generates the file (bytes) and sends it back.
我尝试下载一个文件。该操作由ajax()POST 请求触发。请求以 JSON 格式向控制器发送数据。控制器生成文件(字节)并将其发回。
JavaScript:
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)
- 浏览器应该打开一个下载框,但它没有发生
- 响应在错误处理:ajax 函数部分(但 HTTP 状态为
OK)
So what do I do wrong or what is the proper way to do this?
那么我做错了什么或者这样做的正确方法是什么?
回答by Eugene Naydenov
Just send a URL of file in response and then "visit" it in your successcallback.
只需发送一个文件的 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");
}
});
}
data.fileUrlshould be set in response by server to say client where to get the file.
data.fileUrl应由服务器响应设置,以告诉客户端从何处获取文件。
So your server will send a response with JSON like
因此,您的服务器将使用 JSON 发送响应,例如
{
"fileUrl": "http://mysite.com/files/0123456789"
}
回答by derlinuxer
@will824As you ask I'll post my own solution.
@will824正如你所问,我会发布我自己的解决方案。
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.
我在控制器中使用了一种解决方法并将文件临时保存在文件系统 ( /tmp) 中。我将功能分为 2 个步骤。创建和下载。这不是很好,但对我来说已经足够了。
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:
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
}
});
}
回答by user4532418
If you want download file without change URL, you can call form.submit()programmaticallyinstead of using AJAX.
如果您想在不更改 URL 的情况下下载文件,您可以以form.submit()编程方式调用,而不是使用 AJAX。
JavaScript:
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");
Controller:
控制器:
[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");
}
回答by nickdos
As the comments said you can't do it with an ajax call, but you can do it with plain Javascript.
正如评论所说,你不能用 ajax 调用来完成,但你可以用普通的 Javascript 来完成。
function getLicenseFile() {
var downloadUrl = "${pageContext.request.contextPath}/licenses/rest/downloadLicenseFile";
// (optionally) provide the user with a message that the download is starting
window.location.href = downloadUrl;
}
Note the use of ${pageContext.request.contextPath}, which is preferred over <%=request.getContextPath()%>.
请注意使用${pageContext.request.contextPath},它优于<%=request.getContextPath()%>。
回答by abhinavxeon
Ajax is not going to help you try with hidden form approach
Ajax 不会帮助您尝试隐藏表单方法
<form action='../servletname' method='POST' id='formid'>
<input type='hidden' value='' name='name' id='id'/>
<input type='hidden' value=' ' name='name' id='id' />
</form>
pass you json through form field on click of of your download button submit form
单击您的下载按钮提交表单,通过表单字段传递您的 json
$('#formid').submit();
$('#formid').提交();
then in server side
然后在服务器端
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment; filename=filnemae.fileformat");
ServletOutputStream out = res.getOutputStream();
write on ouput stream then close or flush
在输出流上写入然后关闭或刷新
if you are sending large data through post update postsize in server.xml
如果您通过server.xml 中的post update postsize发送大数据

