文件下载后台报错IllegalStateException: getOutputStream() has already been called
java.lang.IllegalStateException: getOutputStream() has already been called
1 <%@page language="java" contentType="text/html; charset=UTF-8"%> 2 <%@page import="java.util.*,java.io.*"%> 3 <html> 4 <head> 5 <title>下载页面</title> 6 </head> 7 8 <body> 9 <% 10 response.reset(); //记住要记住reset浏览器清空缓存,否则可能会出现乱码情况 11 12 OutputStream o=response.getOutputStream(); 13 14 ResourceBundle res = ResourceBundle.getBundle("test"); //test.properties 15 String XLSFile = res.getString("tempFileRootPath") + "/excel"; 16 File fileLoad=new File(XLSFile,"temp.xls"); 17 18 if(fileLoad.exists()) { 19 response.setHeader("Content-disposition","attachment;filename="+URLEncoder.encode("filename文件名", "UTF-8")+".xls");//文件中文名UTF-8 20 response.setContentType("application/vnd.ms-excel"); 21 long fileLength=fileLoad.length(); 22 String length=String.valueOf(fileLength); 23 response.setHeader("Content_Length",length); 24 25 FileInputStream in = new FileInputStream(fileLoad); 26 OutputStream o = null; 27 try{ 28 in = new FileInputStream(fileLoad); 29 30 o = response.getOutputStream(); 31 out.clear(); 32 out = pageContext.pushBody(); // 33 34 int n=0; 35 byte b[]=new byte[500]; 36 37 while((n=in.read(b))!=-1) { 38 o.write(b,0,n); 39 } 40 o.flush(); 41 42 } catch (Exception e) { 43 out.write("文件导出异常" + e.toString()); 44 } finally { 45 if(in != null) { 46 try { 47 in.close(); 48 } catch(Exception e) {} 49 } 50 if(o != null) { 51 try { 52 o.close(); 53 } catch(Exception e) {} 54 } 55 } 56 } else { 57 out.write("未找到导出的临时文件"); 58 } 59 60 %> 61 62 </body> 63 </html>
原因:
在tomcat中jsp编译成servlet之后在函数_jspService(HttpServletRequest request, HttpServletResponse response)的最后
有一段这样的代码
finally {
if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context);
}
这里是在释放在jsp中使用的对象,会调用response.getWriter(),因为这个方法是和
response.getOutputStream()相冲突的!所以会出现以上异常 IllegalStateException: getOutputStream() has already been called。
jsp中出现此错误一般都是在jsp中使用了输出流(如输出图片验证码,文件下载等),没有妥善处理好的原因。
解决方法:在使用完response.getOutputStream()的后面加上两句(标黄):
out.clear();
out = pageContext.pushBody();
附上javax.servlet.jsp.PageContext方法pushBody()
说明:
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