Java Spring - dynamically generated csv file download response is hanging

jonny bordo picture jonny bordo · Feb 23, 2015 · Viewed 23.2k times · Source

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.

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.

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.

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".

Notice that I don't add a Content-length header, since the file doesn't exist yet, and is being written on the fly.

For writing the csv file I'm using OpenCSV and my code is as follows:

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.

Answer

Thomas picture Thomas · Feb 23, 2015

Can you try returning a null value in your java

return null ;

Or you can try below code also 1. Jquery code upon clicking the submit button

$(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