Java Spring - 动态生成的csv文件下载响应挂起
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28669709/
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
Java Spring - dynamically generated csv file download response is hanging
提问by jonny bordo
On my company's site we have some tables that we need to export to a csv file.
There are some varying parameters, so the csv file needs to be dynamically created on request.
在我公司的网站上,我们有一些表格需要导出为 csv 文件。
有一些不同的参数,因此需要根据请求动态创建 csv 文件。
My problem is that after clicking to download, the response hangs, and waits for the whole file to be created (which can take some time) and only then downloads the entire file in one instant.
我的问题是,单击下载后,响应挂起,并等待创建整个文件(这可能需要一些时间),然后才立即下载整个文件。
I'm using AngularJS, so I'm using window.location = <url_for_file_download>
In order to make the browser download the file.
我使用的是 AngularJS,所以我使用window.location = <url_for_file_download>
In 为了让浏览器下载文件。
On the server side I'm using Java Spring and I've followed all the instructions I could find on the web in order to create a file download controller.
在服务器端,我使用 Java Spring,并且按照我在网上能找到的所有说明来创建文件下载控制器。
My controller code is something like this:
我的控制器代码是这样的:
@RequestMapping(value = "http://yada.yada.yada/csv/myFile.csv", method = RequestMethod.GET)
public @ResponseBody
void getCustomers(HttpServletResponse response,
@RequestParam(required = false) String someParameters)
throws NotAuthorizedException, IOException {
// set headers
setHeaders(response);
// generate writer
CSVWriter write = generateWriter(response);
// get data
List<String[]> data = getData();
// write and flush and all that
.
.
.
}
My code for setting the response headers are:
我设置响应头的代码是:
response.setContentType("text/csv;charset=utf-8");
response.setHeader("Content-Disposition","attachment; filename=\"" + fileName + ".csv\"");
I've also tried adding the following headers:
我还尝试添加以下标题:
response.setHeader("Transfer-Encoding", "Chunked");
response.setHeader("Content-Description", "File Transfer");
and I've also tried setting the Content-type to "application/octet-stream"
.
我还尝试将 Content-type 设置为"application/octet-stream"
.
Notice that I don't add a Content-length
header, since the file doesn't exist yet, and is being written on the fly.
请注意,我没有添加Content-length
标题,因为该文件尚不存在,并且正在即时写入。
For writing the csv file I'm using OpenCSV and my code is as follows:
为了编写 csv 文件,我使用的是 OpenCSV,我的代码如下:
OutputStream resOs = response.getOutputStream();
OutputStream buffOs = new BufferedOutputStream(resOs);
OutputStreamWriter outputWriter = new OutputStreamWriter(buffOs,"UTF-8");
CSVWriter writer = new CSVWriter(outputWriter);
I iterate over the data and write it like so:
我遍历数据并像这样写:
for (String[] row: data) {
writer.writeNext(line);
}
(It's not exactly the code - but this is more or else what happens in the code)
(这不完全是代码 - 但这更多,否则代码中会发生什么)
And at the end I flush and close:
最后我刷新并关闭:
writer.flush();
writer.close();
I also tried flushing after each line I write.
我也尝试在我写的每一行之后冲洗。
So why isn't the file being transferred before it has all been written? Why is my browser (Google chrome) downloading the file in one instant after waiting a long time? And how can I fix this.
那么为什么在文件全部写入之前不传输文件呢?为什么我的浏览器(谷歌浏览器)在等待了很长时间后立即下载了文件?我该如何解决这个问题。
I hope I've added enough code, if there's something missing just please tell me and I'll try to add it here.
我希望我已经添加了足够的代码,如果有什么遗漏请告诉我,我会尝试在这里添加它。
Thank you so much in advance.
非常感谢你。
回答by Thomas
Can you try returning a null value in your java
你能尝试在你的java中返回一个空值吗
return null ;
返回空;
Or you can try below code also 1. Jquery code upon clicking the submit button
或者您也可以尝试以下代码 1. 单击提交按钮后的 Jquery 代码
$(document).ready( function() {
$('#buttonName').click(function(e){
$("#formName").submit();
//alert("The file ready to be downloaded");
});
});
Your controller code
您的控制器代码
@RequestMapping(value="/name",method=RequestMethod.POST)
public ModelAndView downloadCSV(ModelMap model,HttpSession session,@ModelAttribute(value="Pojo") Pojo pojo
,HttpServletRequest request,HttpServletResponse response){
----------------some code----------------
response.setContentType("application/csv");
("application/unknown");
response.setHeader("content-disposition","attachment;filename =filename.csv");
ServletOutputStream writer = response.getOutputStream();
logger.info("downloading contents to csv");
writer.print("A");
writer.print(',');
writer.println("B");
for(int i=0;i<limit;i++){
writer.print(""+pojo.get(i).getA());
writer.print(',');
writer.print(pojo.get(i).getB());
writer.println();
}
writer.flush();
writer.close();
---------------some code-----------
return null;
}
Hope this helps
希望这可以帮助
回答by Paul John
The Controller will wait for the response to be written before the response is send back to the client.
在将响应发送回客户端之前,控制器将等待写入响应。
Here is a nice post with multiple approaches / options outlined
这是一篇很好的帖子,概述了多种方法/选项
Downloading a file from spring controllers
This post talks about flushing the output periodically to help fasten the download.
这篇文章讨论了定期刷新输出以帮助加快下载速度。
how to download large files without memory issues in java
If all you are trying to do is let the user know that the file download is in progress and due soon, I think an Ajax progress status indicaor might be your solution.
如果您要做的只是让用户知道文件下载正在进行中并且即将到期,我认为 Ajax 进度状态指示可能是您的解决方案。
Trigger the ajax call to the back-end to generate the file
Show progress indicator to the user while file is being generated server side
once response is available, file is presented to the user.
触发后端ajax调用生成文件
在服务器端生成文件时向用户显示进度指示器
一旦响应可用,文件就会呈现给用户。
I think something similar is being explored here download file with ajax() POST Request via Spring MVC
我认为这里正在探索类似的东西download file with ajax() POST Request via Spring MVC
Hope this helps!
希望这可以帮助!
Thanks, Paul
谢谢,保罗
回答by medvedev1088
I faced the same issue. The code that didn't work for me was
我遇到了同样的问题。对我不起作用的代码是
@RequestMapping(value = "/test")
public void test(HttpServletResponse response)
throws IOException, InterruptedException {
response.getOutputStream().println("Hello");
response.getOutputStream().flush();
Thread.sleep(2000);
response.getOutputStream().println("How");
response.getOutputStream().flush();
Thread.sleep(2000);
response.getOutputStream().println("are");
response.getOutputStream().flush();
Thread.sleep(2000);
response.getOutputStream().println("you");
response.getOutputStream().flush();
}
The culprit was ShallowEtagHeaderFilter
. When this filter is enabled the response is sent in one chunk. When this filter is diabled the response is send in multiple chunks.
罪魁祸首是ShallowEtagHeaderFilter
。启用此过滤器后,响应将在一个块中发送。当此过滤器被禁用时,响应以多个块发送。
From this thread Tomcat does not flush the response bufferit looks like another possible culprit can be GzipFilter
从这个线程Tomcat不会刷新响应缓冲区它看起来像另一个可能的罪魁祸首GzipFilter