Java Spring - 动态生成的csv文件下载响应正在挂起

时间:2015-02-23 08:40:42

标签: java spring csv opencsv

在我公司的网站上,我们有一些表格需要导出到csv文件 有一些不同的参数,因此需要根据请求动态创建csv文件。

我的问题是,点击下载后,响应挂起,等待创建整个文件(可能需要一些时间),然后只在一个瞬间下载整个文件。

我正在使用AngularJS,所以我使用window.location = <url_for_file_download>为了让浏览器下载文件。

在服务器端我正在使用Java Spring,我已经按照我在网上找到的所有说明来创建文件下载控制器。

我的控制器代码是这样的:

@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
.
.
.
}

我设置响应标头的代码是:

response.setContentType("text/csv;charset=utf-8");
response.setHeader("Content-Disposition","attachment; filename=\"" + fileName + ".csv\"");

我也尝试添加以下标题:

response.setHeader("Transfer-Encoding", "Chunked");
response.setHeader("Content-Description", "File Transfer");

我也尝试将内容类型设置为"application/octet-stream"

请注意,我没有添加Content-length标头,因为该文件尚不存在,并且正在动态编写。

为了编写csv文件我正在使用OpenCSV,我的代码如下:

OutputStream resOs = response.getOutputStream();
OutputStream buffOs = new BufferedOutputStream(resOs);
OutputStreamWriter outputWriter = new OutputStreamWriter(buffOs,"UTF-8");
CSVWriter writer = new CSVWriter(outputWriter);

我迭代数据并按如下方式编写:

for (String[] row: data) {
    writer.writeNext(line);
}

(这不完全是代码 - 但这更多或者代码中发生了什么)

最后我冲洗并关闭:

writer.flush();
writer.close();

在我写完的每一行之后,我也尝试过冲洗。

那么为什么文件在被写入之前都没有被转移? 为什么我的浏览器(谷歌浏览器)在等待很长时间后立即下载文件?我该如何解决这个问题。

我希望我已经添加了足够的代码,如果有什么遗漏,请告诉我,我会尝试在此处添加。

提前非常感谢你。

3 个答案:

答案 0 :(得分:2)

您可以尝试在java中返回空值

返回null;

或者您也可以尝试以下代码 1.单击提交按钮时的Jquery代码

$(document).ready( function() {
     $('#buttonName').click(function(e){
    $("#formName").submit();
     //alert("The file ready to be downloaded");

});
});

您的控制器代码

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

希望这有帮助

答案 1 :(得分:0)

Controller会在响应发送回客户端之前等待写入响应。

这是一篇很好的帖子,其中列出了多种方法/选项

Downloading a file from spring controllers

这篇文章讨论定期刷新输出以帮助确保下载。

how to download large files without memory issues in java

如果您要做的就是让用户知道文件下载正在进行中并且很快就会到期,我认为Ajax进度状态指示器可能是您的解决方案。

  1. 触发对后端的ajax调用以生成文件

  2. 在服务器端生成文件时向用户显示进度指示器

  3. 一旦响应可用,就会向用户显示文件。

  4. 我认为这里正在探讨类似的事情download file with ajax() POST Request via Spring MVC

    希望这有帮助!

    谢谢, 保罗

答案 2 :(得分:0)

我遇到了同样的问题。对我不起作用的代码是

@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();
}

罪魁祸首是ShallowEtagHeaderFilter。启用此过滤器后,响应将在一个块中发送。当此过滤器被禁用时,响应将以多个块的形式发送。

从这个帖子Tomcat does not flush the response buffer看起来另一个可能的罪魁祸首可能是GzipFilter