解决jsp下载文件报错getOutputStream() has already,及无法下载中文名称标题的问题

下载的jsp代码

1、其中紫色部份解决,传值中文乱码问题

2、红色部份解决,下载标题为中文的问题(2 种解决方法)

3、黄色背景部份解决下载点击取消或者下载过程中报错(java.lang.IllegalStateException: getOutputStream() has already been called for this response)异常问题

   转自:http://bbs.csdn.net/topics/300101546。

方法1: 
response.setHeader("Content-Disposition", "attachment; filename=" + java.net.URLEncoder.encode(fileName, "UTF-8")); 
下载的程序里有了上面一句,一般在IE6的下载提示框上将正确显示文件的名字,无论是简体中文,还是日文。但是文字只要超过17个字,就不能下载了。 
一. 通过原来的方式,也就是先用URLEncoder编码,当中文文字超过17个时,IE6 无法下载文件。这是IE的bug,参见微软的知识库文章 KB816868 。原因可能是IE在处理 Response Header 的时候,对header的长度限制在150字节左右。而一个汉字编码成UTF-8是9个字节,那么17个字便是153个字节,所以会报错。而且不跟后缀也不对. 
方法2: 
response.setHeader( "Content-Disposition", "attachment;filename=" + new String( fileName.getBytes("gb2312"), "ISO8859-1" ) ); 
在确保附件文件名都是简 体中文字的情况下,那么这个办法确实是最有效的,不用让客户逐个的升级IE。如果台湾同胞用,把gb2312改成big5就行。但现在的系统通常都加入了 国际化的支持,普遍使用UTF-8。如果文件名中又有简体中文字,又有繁体中文,还有日文。那么乱码便产生了。另外,在上Firefox (v1.0-en)下载也是乱码。 


<%@ page language="java" import="java.util.*" pageEncoding="utf-8" 	contentType="text/html; charset=utf-8"%>
<%@ page import="com.jspsmart.upload.*"%>
<%@page import="java.io.File"%>
<%@ page import="java.io.*"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
	<head>
		<meta http-equiv="pragma" content="no-cache">
		<meta http-equiv="cache-control" content="no-cache">
		<meta http-equiv="expires" content="0">
		<meta http-equiv="Content-Type" content="text/html charset=utf-8">
	</head>
	<body>
		<%
			response.setContentType("text/html");
			request.setCharacterEncoding("utf-8");
			response.setCharacterEncoding("utf-8");
			<span style="color:#cc33cc;">String address = java.net.URLDecoder.decode(request
					.getParameter("address"));
			String filename = java.net.URLDecoder.decode(request
					.getParameter("filename"));</span>
			<span style="color:#cc33cc;">filename = new String(filename.getBytes("ISO-8859-1"), "utf-8");
			address = new String(address.getBytes("ISO-8859-1"), "utf-8");</span>
			System.out.println(filename + address);
			File fileLoad = new File(address);
			System.out.println(fileLoad.getAbsolutePath());
			if (!fileLoad.exists()) {
				out.print(fileLoad.getAbsolutePath() + " File Not Exist !");
				%>
				
				<script type="text/javascript">
	                alert("文件不存在。请联系管理人员");
	                window.history.back();
    			 </script>
				<%
				return;
			}
			javax.servlet.ServletOutputStream ou = response.getOutputStream();   
			java.io.FileInputStream fileInputStream = new FileInputStream(fileLoad);
			try{
			// SmartUpload su = new SmartUpload(); // 新建一个SmartUpload对象 

			//su.initialize(pageContext); // 初始化 

			//su.setContentDisposition(null); 
			// 设定contentDisposition为null以禁止浏览器自动打开文件, 
			//保证点击链接后是下载文件。若不设定,则下载的文件扩展名为 
			//doc时,浏览器将自动用word打开它。扩展名为pdf时,将用acrobat打开
			//response.sendRedirect(path+"/updown/updown_err.jsp");
			//su.downloadFile("/uploadPath/file/liu.doc"); // 下载英文文件

			//su.downloadFile(address, null, filename); // 下载中文文件
			//downloadFile(String sourceFilePathName, String contentType, String destFileName)
			//out.flush();   
			// response.flushBuffer(); 
			//out.clear();
			//out=pageContext.pushBody(); 
			//response.setContentType("text/html");
			if (filename != null && filename.length() > 0) {
				response.setContentType("application/x-msdownload");
<span style="white-space:pre">				</span><span style="background-color: rgb(255, 255, 51);"><span style="color:#ff0000;">// /**此行代码不能改变gbk为Utf-8不然还是一样下载不了,不知道为什么会这样。 */</span></span>
				//response.setHeader("Content-Disposition","attachment; filename="+<span style="color:#ff0000;">new String(filename.getBytes("gbk"), "ISO8859-1" ));</span>
				response.setHeader("Content-Disposition","attachment; filename="+<span style="color:#cc0000;">java.net.URLEncoder.encode(filename, "UTF-8")</span>);
				if (fileInputStream != null) {
					int filelen = fileInputStream.available();
					byte[] a = new byte[filelen];
					fileInputStream.read(a);
					ou.write(a);
				}
				<span style="background-color: rgb(255, 255, 51);">fileInputStream.close();
				ou.close();</span>
			}
				<span style="background-color: rgb(255, 255, 51);">out.clear();
				out = pageContext.pushBody();</span>
		}catch(Exception e){
			<span style="background-color: rgb(255, 255, 0);">fileInputStream.close();
			ou.close();
			out.clear();
			out = pageContext.pushBody();</span>
		%>
		<script type="text/javascript">
                   
                   alert("下载文件异常,请联系管理人员");
                   window.history.back();
                    
        </script>
		<%
		}
		%>

	</body>
</html>


### 解决方案: 当在Java应用中多次调用 `response.getOutputStream()` 方法时,会抛出 `IllegalStateException` 异常,这是因为HTTP响应流只能被一次性地读取或写入。 **原因分析:** 每次调用 `response.getWriter()` 或 `response.getOutputStream()` 都会在HTTP响应中创建一个新的输出流。如果尝试在同一个请求生命周期内多次调用这些方法(例如,在响应流已被关闭并用于写入数据之后再次尝试),将会触发 `IllegalStateException` 异常。 ### 解决步骤: #### 第一步:识别错误场景 确保你的代码只在一个特定的情况下调用 `response.getOutputStream()` 或 `response.getWriter()`,并且这个操作应该发生在整个HTTP请求的响应过程中。 #### 第二步:封装输出流 考虑使用流的包装类来管理输出流的生命周期。例如,可以创建一个 `PrintWriter` 或者 `BufferedOutputStream` 的包装器,确保输出流在必要时打开并在完成后关闭。 ```java public class SafeOutputStream extends OutputStream { private final PrintWriter writer; public SafeOutputStream(HttpServletResponse response) { // 根据实际情况调整编码方式 this.writer = new PrintWriter(response.getOutputStream(), "UTF-8"); } @Override public void write(int b) { writer.write(b); } @Override public void flush() { writer.flush(); } @Override public void close() { writer.close(); } } ``` #### 第三步:替换原方法调用 在需要输出数据的地方,使用上面定义的 `SafeOutputStream` 替代直接调用 `response.getOutputStream()` 或 `response.getWriter()`。这确保了输出流的正确管理和避免了重复调用。 ```java HttpServletResponse response = ...; // 获取Response对象 SafeOutputStream safeStream = new SafeOutputStream(response); try { safeStream.print("Hello, World!"); // 写入数据 safeStream.flush(); // 刷新缓冲区 } finally { safeStream.close(); // 关闭流 } ``` ### 相关问题: 1. 当在Java中处理HTTP响应时,如何有效地管理输出流以防止资源泄露? 2. Java Web开发中,如何优雅地处理多次调用`response.getOutputStream()`导致的异常情况? 3. 使用第三方库如Jxls时,遇到`IllegalStateException: getOutputStream() has already been called for this response`错误,应采取哪些策略进行排查和修复?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值