I'm trying to assemble a CSV file from some DB data and send it to the client from my Spring MVC controller (and associated services). I'm using SuperCSV to handle the writing and output: http://supercsv.sourceforge.net/
So, here's the controller method:
@RequestMapping(value="/getFullReqData.html", method = RequestMethod.GET)
public void getFullData(HttpSession session, HttpServletRequest request, HttpServletResponse response) throws IOException{
logger.info("INFO: ******************************Received request for full Req data dump");
List<Requirement> allRecords = reqService.getFullDataSet(ProjectService.getProjectID((String)session.getAttribute("currentProject")));
response.setContentType("text/csv;charset=utf-8");
response.setHeader("Content-Disposition","attachment; filename=nistData.csv");
OutputStream fout= response.getOutputStream();
OutputStream bos = new BufferedOutputStream(fout);
OutputStreamWriter outputwriter = new OutputStreamWriter(bos);
ICsvBeanWriter writer = new CsvBeanWriter(outputwriter, CsvPreference.EXCEL_PREFERENCE);
try {
final String[] header = new String[] {
"ReqID",
"ColName1",
"ColName2",
"ColName3",
"ColName4",
"ColName5",
"ColName6",
"ColName7",
"ColName8",
"ColName9",
"ColName10" };
// the actual writing
writer.writeHeader(header);
for(Requirement aCR : allRecords){
writer.write(aCR, header);
}
} finally {
writer.close();
}
};
This is actually moving forward and getting the response to the client browser which triggers the download of the csv file.
Two problems:
1) I'm getting a pile of server-side exception spewage (below)
2) The CSV file has only the headers in it and no data, despite the allRecords list showing as fully populated in the debugger.
I'm hoping the failure-to-populate is caused by the exception, but I'm suspicious. Exception trace:
SEVERE: Servlet.service() for servlet jsp threw exception
java.lang.IllegalStateException: getOutputStream() has already been called for this response
at org.apache.catalina.connector.Response.getWriter(Response.java:633)
at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:214)
at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:105)
at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:105)
at org.apache.jasper.runtime.JspWriterImpl.initOut(JspWriterImpl.java:125)
at org.apache.jasper.runtime.JspWriterImpl.flushBuffer(JspWriterImpl.java:118)
at org.apache.jasper.runtime.PageContextImpl.release(PageContextImpl.java:182)
at org.apache.jasper.runtime.JspFactoryImpl.internalReleasePageContext(JspFactoryImpl.java:123)
at org.apache.jasper.runtime.JspFactoryImpl.releasePageContext(JspFactoryImpl.java:80)
at org.apache.jsp.error_jsp._jspService(error_jsp.java:102)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
The exception looks to get passed along as I'm seeing it 4 times per invocation of this method.
All documentation I've found has people who are embedding their response.getOutputStream() inside scriptlets instead of being in a servlet. The method I've got up above is inside the Spring MVC controller, so the advise of "move it to a servlet!" doesn't seem to apply here. From what I can tell, I'm only invoking the response.getOutputStream() one time, and the method is blowing up on the first call.
I'm stumped. Help?