如果用户下载的文件是中文名,或者是在下载前检查用户的权限,就要使用Struts2提供的文件下载。在前台页面上提供一个链接,这个链接指向一个存在于服务器上的文件,并且文件的名字是中文名称,对中文名称进行URL编码。以下是download.jsp文件的内容:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@page import="java.net.URLEncoder"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>文件下载</title>
</head>
<body>
<a href="struts2download.action?fileName=<%=URLEncoder.encode("download中文.doc","UTF-8") %>">下载</a>
</body>
</html>
Action类:
package com.jason.web.action;
import java.io.InputStream;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class DownLoadAction extends ActionSupport{
private static final long serialVersionUID = -6103161491484708345L;
private String fileName; // 要下载的文件的名称
private String downDir;// 下载文件夹由struts在配置文件中注入
private String fileEncoding;// 文件名 字符集
// 省略Getter、Setter方法
public InputStream getDownloadStream() throws Exception {
// 对于get方式提交的数据需要我们手工进行转码
fileName = new String(fileName.getBytes("iso-8859-1"), fileEncoding);
// 取得文件的路径
String filePath = downDir + "/" + fileName;
// System.out.println(filePath);
return ServletActionContext.getServletContext().getResourceAsStream(filePath);
}
@Override
public String execute() throws Exception {
return SUCCESS;
}
}
struts.xml配置文件
<action name="struts2download" class="com.jason.web.action.DownLoadAction">
<param name="downDir">/download</param>
<param name="fileEncoding">UTF-8</param>
<result type="stream">
<param name="inputName">downloadStream</param>
<!--下载文件的缓冲区大小-->
<param name="bufferSize">4096</param>
<!--
如果想让用户直接使用浏览器打开,我们可以直接指定正确的类型。
如果不好确定类型,可以使用application/octet-stream,表示二进制流
-->
<param name="contentType">application/octet-stream;charset=iso-8859-1</param>
<param name="contentDisposition">attachment;filename="${fileName}"</param>
</result>
</action>
运行OK!但是当取消下载时会报错
java.lang.IllegalStateException
异常原因分析: stream对应的类是org.apache.struts2.dispatcher.StreamResult,该类的处理过程如下:1。配置其中result标签下的各个参数2。从服务器中获取输入流,并同时与客户端建立输出流(服务器与客户端链接通过Socket进行连接)3。当点击“保存”或“打开”时,开始传输数据。如果点击“取消”,关闭所有的流。 这里要注意的是,但是实际发现Socket并没有断开!并且流也没有关闭!这一点非常重要! 所以在JSP容器通过Response获取输出流之前,前面的流并没有关闭,所以会造成该异常的报出。
解决办法:
需要下载struts2-sunspoter-stream-1.0.jar,并复制在/WEB-INF/lib下
struts.xml配置修改如下:
<result-types>
<result-type name="streamx" class="com.sunspoter.lib.web.struts2.dispatcher.StreamResultX"/>
</result-types>
<action name="struts2download" class="com.jason.web.action.DownLoadAction">
<param name="downDir">/download</param>
<param name="fileEncoding">UTF-8</param>
<result type="streamx">
<param name="inputName">downloadStream</param>
<!--下载文件的缓冲区大小-->
<param name="bufferSize">4096</param>
<!--
如果想让用户直接使用浏览器打开,我们可以直接指定正确的类型。
如果不好确定类型,可以使用application/octet-stream,表示二进制流
-->
<param name="contentType">application/octet-stream;charset=iso-8859-1</param>
<param name="contentDisposition">attachment;filename="${fileName}"</param>
</result>
</action>
只需添加一个result-type,将原有的result中type改为“streamx”,其他一律不变,在这种情况下,点击“取消”的同时也关闭了流,不会再报出该异常。再点击取消会出现警告
WARN StreamResult:45 - StreamResultX Warn : socket write error
如果出现该警告说明正确执行,该警告说明,Socket非正常中断,但是流确实已经关闭,自此再也不用看到上面出现的讨厌异常结果。