【问题标题】:Spring MVC Controller code: getOutputStream() has already been called for this responseSpring MVC 控制器代码:已为此响应调用 getOutputStream()
【发布时间】:2012-09-01 18:24:16
【问题描述】:

我正在尝试从一些数据库数据中组装一个 CSV 文件,并将其从我的 Spring MVC 控制器(和相关服务)发送到客户端。我正在使用 SuperCSV 处理写入和输出:http://supercsv.sourceforge.net/

所以,这里是控制器方法:

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

这实际上是向前移动并获得对触发下载 csv 文件的客户端浏览器的响应。

两个问题:

1) 我收到一堆服务器端异常信息(下)

2) 尽管 allRecords 列表在调试器中显示为完全填充,但 CSV 文件中只有标题,没有数据。

我希望填充失败是由异常引起的,但我很怀疑。异常跟踪:

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)

每次调用此方法时,我都会看到 4 次异常。

我发现的所有文档中都有人将他们的 response.getOutputStream() 嵌入到 scriptlet 中,而不是放在 servlet 中。我上面提到的方法是在 Spring MVC 控制器内部,所以建议“将它移到 servlet!”似乎不适用于这里。据我所知,我只调用了一次 response.getOutputStream(),并且该方法在第一次调用时就崩溃了。

我被难住了。帮忙?

【问题讨论】:

  • 尽量不要关闭输出流。 stackoverflow.com/questions/1829784/…
  • 那里有很好的信息,但不幸的是,这不是我问题的根源。我删除了它以防止将来出现任何问题,但它似乎不会导致我当前的 IllegalStateException。

标签: java spring exception spring-mvc csv


【解决方案1】:

您的流程可能在请求映射方法的某处引发异常 - 可能在 writer.write(aCR, header); 中,然后进入 finally 块,关闭响应流,然后异常冒泡到 servlet,它试图通过一个错误页面(检查您的 web.xml error-page 标签),因为响应流已关闭,因此无法干净地呈现错误 jsp,因此您会看到异常消息。

如果您可以在控制器中捕获异常并打印堆栈跟踪以查看在写入输出流时控制器中可能出现的问题,那就太好了。

【讨论】:

  • 你成功了。异常实际上来自 CsvBeanWriter,因为我尝试编写的对象具有布尔成员变量的非标准方法名称。当库试图反映和调用它时,它找不到它并且异常被屏蔽,然后错误报告了我的 outputStream 的 b/c 在 finally 调用中被关闭。先生厉害。
【解决方案2】:

你可以让它与 printWriter 一起工作吗:

    response.setContentType("application/vnd.ms-excel;charset=UTF-8");
    response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + ".xls\"");
    PrintWriter out = response.getWriter();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-17
    • 2012-08-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多