• java.lang.IllegalStateException: getOutputStream() has already been called for this response


    1.问题描述:

      在导出数据库某时间段的数据,然后获得Excel,虽然页面可以顺利导出,但后台报错如下:(虽然不影响导出效果,但看到后台的异常,内心还是不舒服的)

    严重: Servlet.service() for servlet [jsp] in context with path [/exportExcel] threw exception [java.lang.IllegalStateException: getOutputStream() has already been called for this response] with root cause
    java.lang.IllegalStateException: getOutputStream() has already been called for this response
        at org.apache.catalina.connector.Response.getWriter(Response.java:678)
        at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:213)
        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:194)
        at org.apache.jasper.runtime.JspFactoryImpl.internalReleasePageContext(JspFactoryImpl.java:126)
        at org.apache.jasper.runtime.JspFactoryImpl.releasePageContext(JspFactoryImpl.java:80)
        at org.apache.jsp.export_jsp._jspService(export_jsp.java:566)
        at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
        at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:439)
        at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:395)
        at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:339)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)

     从字义上分析:getOutputStream()已经调用了这个响应,就是重复被调用引起的异常。

    2.问题分析:

      在tomcat下jsp出现该错误一般都是在使用了输出流(如输出图片验证码,文件下载等)。

      产生这样的异常原因:是web容器生成的servlet代码中有out.write(""),这个和JSP中调用的response.getOutputStream()产生冲突。即Servlet规范说明,不能既调用response.getOutputStream(),又调用response.getWriter(),无论先调用哪一个,在调用第二个时候应会抛出IllegalStateException,因为在jsp中,out变量实际上是通过response.getWriter得到的,你的程序中既用了response.getOutputStream,又用了out变量,故出现以上错误。

    3.解决方案:

      在调用 response.getOutputStream()之前,清空缓存的内容,并返回一个新的BodyContext,更新PageContext的out属性的内容。

    ...
    <body>
    <%
        String startDate = request.getParameter("startDate");
        String endDate = request.getParameter("endDate");
        System.out.println("起始时间:"+startDate+"  &&&  终止时间"+endDate);
        if(startDate== null || startDate.equals("")){
            startDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
            System.out.println("起始时间:"+startDate);
        }
        if(endDate== null || endDate.equals("")){
            endDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
            System.out.println(endDate);
        }else{
            endDate = endDate+" 23:59:59";
            System.out.println("终止时间:"+endDate);
        }
        String fileName = new Date().getTime()+".xls";
        response.reset();
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-disposition", "inline;filename="+fileName);
        out.clear();      //清空缓存的内容
        out=pageContext.pushBody();  //更新PageContext的out属性的内容
        writeExcel(response.getOutputStream(),startDate,endDate);
    %>
    </body>
    </html>
    <%!    //相当于全局声明,是jsp页面中一些变量和方法的声明时用到的;上面没有感叹号的只是普通的语句 jsp代码块
        public static void writeExcel(OutputStream os,String startDate,String endDate){
            try{
                WritableWorkbook wwb = Workbook.createWorkbook(os);
                WritableSheet sheet = wwb.createSheet("导出表单", 0);  //第一个sheet
                // 设置字体
                WritableFont redfont = new WritableFont(WritableFont.createFont("微软雅黑"),10, WritableFont.BOLD, false, UnderlineStyle.NO_UNDERLINE, Colour.RED);
                // **************往工作表中添加数据*****************
                WritableCellFormat red_key = new WritableCellFormat(redfont);
                WritableFont black_font = new WritableFont(WritableFont.createFont("微软雅黑"),10, WritableFont.BOLD, false, UnderlineStyle.NO_UNDERLINE,Colour.BLACK);
                WritableCellFormat black_key = new WritableCellFormat(black_font);
                // **************往工作表中添加表头*****************
    ...
    ...

    4.扩展

      上面代码,根本没有用到out,为什么可以调用out.clear和pageContext ? 因为这都是JSP的内置对象,可以随时使用。

      JSP九大内置对象(在JSP页面上可直接使用,html页面不能用):

      4.1 page:一个jsp就是一个servlet类,就是一个java类,java类的this对象,对应JSP的page对象;

      4.2 pageContext :当前页对象

      4.3 application:上下文对象

      4.4 config :servlet生命周期 1.初始化

      4.5 request:请求。servlet生命周期 2.service方法:请求,响应

      4.6 response:响应

      4.7 session:请求对应session,有了request就可以得到session,session=request.getSession();

      4.8 out:response对应out对象--》这个就是这个异常根本所在;

      4.9 exception:异常对象(有代码存在就会有异常存在)。

  • 相关阅读:
    centos下安装nethogs
    Nginx+Tomcat反向代理利用certbot实现https
    Mysql主从复制读写分离
    短链接及关键字过滤ac自动机设计思路
    接口访问加密和限频方案
    算法笔记
    redis原理及使用
    memcached原理
    Spring中AOP的两种代理方式(Java动态代理和CGLIB代理-转载
    基于注解的Spring AOP的配置和使用--转载
  • 原文地址:https://www.cnblogs.com/qingmuchuanqi48/p/12072415.html
Copyright © 2020-2023  润新知