問題解決:這個迴應response的getOutputStream()已經被呼叫過
做個登入時的驗證碼,執行時出現以下錯誤:
嚴重: Servletjsp的Servlet.service()發生意外(exception) java.lang.IllegalStateException: 這個迴應response的getOutputStream()已經被呼叫過
原始碼如下:
<%@ page language="java" contentType="image/jpeg; charset=gb2312" pageEncoding="gb2312"%>
<%@ page import="java.awt.*,java.awt.image.*" %>
<%@ page import="java.util.*,javax.imageio.*" %>
<%! Color getRandColor(int fc,int bc)
{
Random r=new Random();
if(fc>255) fc=255;
if(bc>200) bc=255;
int red=fc+r.nextInt(bc-fc);
int green=fc+r.nextInt(bc-fc); i
nt blue=fc+r.nextInt(bc-fc);
return new Color(red,green,blue);
}%>
<% //設定頁面不快取
response.setHeader("Pragma","No-cache"); response.setHeader("cache-Control","no-cache"); response.setDateHeader("Expires",0);
//建立隨機類
Random r=new Random();
//在記憶體中建立影象,寬度,高度
int width=80,height=30;
BufferedImage pic=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//獲取圖形上下文環境
Graphics gc=pic.getGraphics();
//設定背景顏色並進行填充
gc.setColor(getRandColor(200,250));
gc.fillRect(0,0,width,height);
//設定圖形上下文環境字型
gc.setFont(new Font("Times New Roman",Font.PLAIN,20));
//畫邊框
//gc.setColor(new Color(1));
//gc.drawRect(0,0,width-1,height-1);
//隨機產生200條幹擾直線,使影象中的認證碼不易被其他分析程式探測
gc.setColor(getRandColor(160,200));
for(int i=0;i<200;i++)
{ int x1=r.nextInt(width);
int y1=r.nextInt(height);
int x2=r.nextInt(15);
int y2=r.nextInt(15);
gc.drawLine(x1,y1,x1+x2,y1+y2);
}
//隨即產生100個干擾點
gc.setColor(getRandColor(120,240));
for(int i=1;i<100;i++)
{ int x=r.nextInt(width);
int y=r.nextInt(height);
gc.drawOval(x,y,0,0);
}
//隨機產生四位數字的驗證碼
String RS=""; String rn="";
for(int i=0;i<4;i++)
{ //產生十以內隨機數字
rn=String.valueOf(r.nextInt(10));
RS+=rn;
//將認證碼用drawString函式顯示到影象裡
//剛開始寫的沒下面這句結果字型顏色很淡幾乎看不清
gc.setColor(new Color(20+r.nextInt(110),20+r.nextInt(110),20+r.nextInt(110)));//使字型顏色效果明顯 gc.drawString(rn,13*i+16,16);
}
//釋放圖形上下文環境 gc.dispose();
//將認證碼RS存入session中共享
session.setAttribute("random",RS);
//輸出生成後的圖象到頁面
ImageIO.write(pic,"JPEG",response.getOutputStream());
// out.clear();//清除緩衝區裡的資料,但不把資料寫到客戶端裡去
// out = pageContext.pushBody();// 重新得到out物件
%>
去掉最後兩句的註釋後,就不再出錯了。原因如下:
在tomcat5下jsp中出現此錯誤一般都是在jsp中使用了輸出流(如輸出圖片驗證碼,檔案下載等),沒有妥善處理好的原因。
具體的原因就是在tomcat中jsp編譯成servlet之後在函式_jspService(HttpServletRequest request, HttpServletResponse response)的最後有一段這樣的程式碼 finally { if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context); } 這裡是在釋放在jsp中使用的物件,會呼叫response.getWriter(),因為這個方法是和response.getOutputStream()相沖突的!所以會出現以上這個異常。
簡單的說就是web容器生成的servlet程式碼中有out.write(""),這個和JSP中呼叫的 response.getOutputStream()產生衝突.即Servlet規範說明,不能既呼叫 response.getOutputStream(), 又呼叫response.getWriter(),無論先呼叫哪一個,在呼叫第二個時候應會丟擲 IllegalStateException, 因為在jsp中,out變數實際上是通過response.getWriter得到的, 程式中既用了 response.getOutputStream,又用了out變數,故出現以上錯誤。
然後當然是要提出解決的辦法,其實挺簡單的
在使用完輸出流以後呼叫以下兩行程式碼即可: out.clear(); out = pageContext.pushBody();