posts - 262,  comments - 221,  trackbacks - 0
《轻量级J2EE企业应用实战》一书的第2章有一个使用SerlvetResponse输出图像的例子,代码如下:

<%
  BufferedImage image 
= new BufferedImage(400400, BufferedImage.TYPE_INT_RGB);
  Graphics g 
=
 image.getGraphics();
  g.fillRect(
0,0,400,400
);
  g.setColor(
new Color(255,0,0
));  
  g.fillArc(
20,20,100,100,30,120
);
  g.setColor(
new Color(0,255,0
));
  g.fillArc(
20,20,100,100,150,20
);
  g.setColor(
new Color(0,0,255
));
  g.fillArc(
20,20,100,100,270,120
);
  g.setColor(
new Color(0,0,0
));
  g.drawString(
"red:climb" , 30080
);
  g.drawString(
"green:swim"300120
);
  g.drawString(
"blue:jump"300160
);
  ImageIO.write(image, 
"bmp"
, response.getOutputStream());
  
//
out.clear();
  
//out = pageContext.pushBody();

%>

在Tomcat下运行时抛出如下异常:

    at org.apache.catalina.connector.Response.getWriter(Response.java:601)
    at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:196)
    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:
185
)
    at org.apache.jasper.runtime.JspFactoryImpl.internalReleasePageContext(JspFactoryImpl.java:
116
)
    at org.apache.jasper.runtime.JspFactoryImpl.releasePageContext(JspFactoryImpl.java:
76
)
    
at org.apache.jsp.pages.drawImage_jsp._jspService(drawImage_jsp.java:84)
    at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:
803
)
    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:
328
)
    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:
315
)
    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:
265
)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:
803
)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:
269
)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:
188
)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:
210
)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:
174
)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:
127
)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:
117
)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:
108
)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:
151
)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:
870
)
    at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:
665
)
    at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:
528
)
    at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:
81
)
    at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:
685
)
    at java.lang.Thread.run(Thread.java:
595)

查看转换后的JSP代码,发现第84行如下(绿色高亮处):

  public void _jspService(HttpServletRequest request, HttpServletResponse response)
        
throws java.io.IOException, ServletException 
{

    JspFactory _jspxFactory 
= null
;
    PageContext pageContext 
= null
;
    HttpSession session 
= null
;
    ServletContext application 
= null
;
    ServletConfig config 
= null
;
    JspWriter out 
= null
;
    Object page 
= this
;
    JspWriter _jspx_out 
= null
;
    PageContext _jspx_page_context 
= null
;


    
try 
{
      _jspxFactory 
=
 JspFactory.getDefaultFactory();
      response.setContentType(
"text/html; charset=UTF-8"
);
      pageContext 
= _jspxFactory.getPageContext(this
, request, response,
                  
nulltrue8192true
);
      _jspx_page_context 
=
 pageContext;
      application 
=
 pageContext.getServletContext();
      config 
=
 pageContext.getServletConfig();
      session 
=
 pageContext.getSession();
      out 
=
 pageContext.getOut();
      _jspx_out 
=
 out;

      out.write(
"\r\n"
);
      out.write(
"\n"
);
      out.write(
"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");

      out.write("<html>\n");
      out.write(
"<head>\n"
);
      out.write(
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n"
);
      out.write(
"<title>Draw Image</title>\n"
);
      out.write(
"</head>\n"
);
      out.write(
"<body>\n"
);
      out.write(
"\r\n"
);

  BufferedImage image 
= new BufferedImage(400400
, BufferedImage.TYPE_INT_RGB);
  Graphics g 
=
 image.getGraphics();
  g.fillRect(
0,0,400,400
);
  g.setColor(
new Color(255,0,0
));  
  g.fillArc(
20,20,100,100,30,120
);
  g.setColor(
new Color(0,255,0
));
  g.fillArc(
20,20,100,100,150,20
);
  g.setColor(
new Color(0,0,255
));
  g.fillArc(
20,20,100,100,270,120
);
  g.setColor(
new Color(0,0,0
));
  g.drawString(
"red:climb" , 30080
);
  g.drawString(
"green:swim"300120
);
  g.drawString(
"blue:jump"300160
);
  ImageIO.write(image, 
"bmp"
, response.getOutputStream());
  
//
out.clear();
  
//out = pageContext.pushBody();


      out.write(
"\r\n");
      out.write(
"</body>\n"
);
      out.write(
"</html>"
);
    }
 catch (Throwable t) {
      
if (!(t instanceof SkipPageException))
{
        out 
=
 _jspx_out;
        
if (out != null && out.getBufferSize() != 0
)
          out.clearBuffer();
        
if (_jspx_page_context != null
) _jspx_page_context.handlePageException(t);
      }

    }
 finally {
      
if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context);
    }

  }

我们看到在JSP页面释放资源的时候,调用了ServetResponse.getWriter()方法,之后程序即抛出异常了,查看Servlet的API发现问题: 
public java.io.PrintWriter getWriter()
throws java.io.IOException
Returns a PrintWriter object that can send character text to the client. The PrintWriter uses the character encoding returned by getCharacterEncoding(). If the response's character encoding has not been specified as described in getCharacterEncoding (i.e., the method just returns the default value ISO-8859-1), getWriter updates it to ISO-8859-1.

Calling flush() on the PrintWriter commits the response.

Either this method or getOutputStream() may be called to write the body, not both.

 

Returns:
a PrintWriter object that can return character data to the client
Throws:
UnsupportedEncodingException - if the character encoding returned by getCharacterEncoding cannot be used
java.lang.IllegalStateException - if the getOutputStream method has already been called for this response object
java.io.IOException - if an input or output exception occurred
See Also:
getOutputStream(), setCharacterEncoding(java.lang.String)
如API所言,由于ServletResponse.getOutputStream()方法和该方法都有可能被调用,来输出JSP页面的内容,如果其中的一个方法被调用了,再调用另一个方法就会抛出异常。

解决方法如下:

将JSP页面的最后两行代码的注释去掉,这两行代码的作用如下:

out.clear():清空缓存的内容。

pageContext.pushBody():参考API

public BodyContent pushBody()
Return a new BodyContent object, save the current "out" JspWriter, and update the value of the "out" attribute in the page scope attribute namespace of the PageContext.

 

Returns:
the new BodyContent

·返回一个新的BodyContent(代表一个HTML页面的BODY部分内容)
·保存JspWriter实例的对象out
·更新PageContext的out属性的内容



-------------------------------------------------------------
生活就像打牌,不是要抓一手好牌,而是要尽力打好一手烂牌。
posted on 2008-01-19 22:24 Paul Lin 阅读(43322) 评论(10)  编辑  收藏 所属分类: J2EE基础


FeedBack:
# re: getOutputStream() has already been called for this response的解决方法
2008-08-19 20:02 | wasw100
不错,对jsp有了更深的理解了,收藏了  回复  更多评论
  
# re: getOutputStream() has already been called for this response的解决方法
2008-12-23 11:36 | 常青
太感谢了。这个问题郁闷了我们几个月,后来还是改了设计给绕过去的。现在可以按照正常的设计修改代码了。再次谢过了。  回复  更多评论
  
# re: getOutputStream() has already been called for this response的解决方法
2009-05-06 10:06 | dongzgguang
非常感谢  回复  更多评论
  
# re: getOutputStream() has already been called for this response的解决方法[未登录]
2010-05-17 09:09 | Jordan
谢谢啊!
问题解释的很清楚, 解决方案也正确!
希望以后多多交流, 我QQ914132900  回复  更多评论
  
# re: getOutputStream() has already been called for this response的解决方法
2010-07-19 11:32 | GAME OVER
想问下博主大哥,小弟也遇到了这个情况,但是在后面加了那两句也不行!
后来我也去看了下提示错误生成的servlet文件,但是有一点不同的是我的只有这
_jspxFactory.releasePageContext(_jspx_page_context);
没有前面的if语句,直接在生成servlet的文件中加if语句,但是刷新页面还是会有异常的。实在不懂是怎么回事,只好想请教下大哥!
小弟Email:ice-_-wind@163.com
劳烦大哥看到了回复下!
  回复  更多评论
  
# re: getOutputStream() has already been called for this response的解决方法[未登录]
2010-11-27 17:37 | test
错误解决不了,我照你的做,还是一样!!  回复  更多评论
  
# re: getOutputStream() has already been called for this response的解决方法
2011-04-06 20:21 | 沈林楠
我内牛满面啊,郁闷我一天的问题终于解决了,爱死你了  回复  更多评论
  
# re: getOutputStream() has already been called for this response的解决方法
2011-10-07 10:02 | 三等功
我这样用了还是不行啊
  回复  更多评论
  
# re: getOutputStream() has already been called for this response的解决方法
2013-09-17 13:31 | 冰凝火龙吟
谢谢指点。。。。。。  回复  更多评论
  
# re: getOutputStream() has already been called for this response的解决方法
2014-01-07 14:52 | Hucc

只有注册用户登录后才能发表评论。


网站导航:
 
<2008年1月>
303112345
6789101112
13141516171819
20212223242526
272829303112
3456789

常用链接

留言簿(21)

随笔分类

随笔档案

BlogJava热点博客

好友博客

搜索

  •  

最新评论

阅读排行榜

评论排行榜