如果对于实现文件的下载有了基础的认识,那么就可以知道文件的下载其实就是HTTP请求头的控制,可以直接使用Servlet实现,也可以使用Struts2框架实现。相较于Servlet需要在代码中设置相应的参数,而Struts2框架提供的下载只需要做一些相应的配置,显得相对简单。具体步骤如下:
1.搭建简单的Struts2项目(参考Struts2的Example)
2.书写文件列表显示的Action类(ListFileAction)
3.显示文件名列表界面(list2.jsp)
3.文件下载处理类(DownloadFileAction)
4.配置文件的实现(struts.xml)
分析:
1.在struts2中实现文件下载Action的返回值使用的是stream,这点可以从Struts2的文档中就可以看出:
[b][color=red]Stream Result Used to stream an InputStream back to the browser (usually for file downloads) [/color][/b]
2.通过查看struts2.x的核心jar包中的struts-default.xml文件中,发现其中有一个名为stream的文件下载拦截器
透过此类不难发现,其实Struts2实现文件下载的本质与普通Servlet是一致的,只是Struts2通过拦截器和配置文件进行工作。在下载Action的方法中有个固定的写法就是:
至此可以看见Struts2框架实现文件下载其实原理和Servlet文件下载的方式是一致的,也就完全理解了Struts2实现文件下载为什么要配置相应的参数了
附上关于配置文件中参数的解释,免得以后自己忘记:
[color=blue]contentType - the stream mime-type as sent to the web browser (default = text/plain).
contentLength - the stream length in bytes (the browser displays a progress bar).
contentDisposition - the content disposition header value for specifing the file name (default = inline, values are typically attachment;filename="document.pdf".
inputName - the name of the InputStream property from the chained action (default = inputStream).
bufferSize - the size of the buffer to copy from input to output (default = 1024).
allowCaching - if set to 'false' it will set the headers 'Pragma' and 'Cache-Control' to 'no-cahce', and prevent client from caching the content. (default = true)
contentCharSet - if set to a string, ';charset=value' will be added to the content-type header, where value is the string set. If set to an expression, the result of evaluating the expression will be used. If not set, then no charset will be set on the header [/color]
1.搭建简单的Struts2项目(参考Struts2的Example)
2.书写文件列表显示的Action类(ListFileAction)
public class ListFileAction implements ServletRequestAware, ServletContextAware {
private HttpServletRequest request;
private ServletContext application;
private List<String> listNames = new ArrayList<String>();// 可以下载的文件名集合
public String execute() {
getFiles();
return "success";
}
public void getFiles() {
// 指定文件上传目录就是文件下载的目录
String pathname = ServletActionContext.getServletContext().getRealPath(
"/upload");
File filedir = new File(pathname);// 新建文件
if (filedir.exists() && filedir.isDirectory()) {// 判断是否为目录,是则遍历文件
File[] files = filedir.listFiles();
for (File file : files) {
listNames.add(file.getName());// 将文件名放入集合中
}
}
request.setAttribute("names", listNames);// 将文件名集合放入request作用域中
}
@Override
public void setServletContext(ServletContext context) {
this.application = context;
}
@Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
}
把文件列表放入request作用域中,所以在此Action中实现了ServletRequestAware, ServletContextAware这两个接口,使用依赖注入的方式获得request,也可以使用以下两种方式直接操作:
ActionContextActionContext.getContext().put("names", listNames);
ServletActionContext.getRequest().setAttribute("names", listNames);
以上两种方式都可以将names放到request的作用域中
3.显示文件名列表界面(list2.jsp)
<%
List<String> fileNames = (List<String>) request.getAttribute("names");
for (String name : fileNames) {
%>
<a href="download.action?filename=<%=name%>"><%=name%></a><br/>
<%}%>
获取到ListFileAction放到request作用域的names的值,然后遍历出来,使用超链接的形式实现文件下载的请求
3.文件下载处理类(DownloadFileAction)
public class DownloadFileAction implements ServletRequestAware,
ServletContextAware {
private HttpServletRequest request;
private ServletContext application;
public InputStream getDownloadFile() {
String fileName = "";
try {
fileName = new String(request.getParameter("filename").getBytes(
"ISO-8859-1"), "GB2312");// 获取文件名,并且进行转码,防止乱码
System.out.println(fileName);
} catch (Exception e) {
e.printStackTrace();
}
return ServletActionContext.getServletContext().getResourceAsStream(
"/upload/" + fileName);
}
public String execute() {
return "success";
}
@Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
@Override
public void setServletContext(ServletContext context) {
this.application = context;
}
}
在下载处理类中获取到文件名后拼接到下载路径实现对某个文件的下载。
4.配置文件的实现(struts.xml)
<!-- 文件下载action -->
<action name="download" class="changluo.file.DownloadFileAction">
<!-- 必须设置type为stream类型 -->
<result name="success" type="stream">
<param name="contentType"></param>
<!-- 设置http请求头并且设置attachment属性以附件的方式打开,
如果没有设置此属性,则以inputStream的方式直接在浏览器打开;
并且filename设置下载时,文件显示的名称 -->
<param name="contentDisposition">
attachment;filename="dddd.txt"
</param>
<!-- inputName的属性设置要依据action中的public InputStream getDownloadFile();
方法类设定,就是此方法名get后面的部分-->
<param name="inputName">downloadFile</param>
</result>
</action>
<!-- 显示文件列表 -->
<action name="listFile" class="changluo.file.ListFileAction">
<result name="success">/list2.jsp</result>
<result name="input">/index.jsp</result>
</action>
以上就构成了Struts2文件下载的基本组成部分。
分析:
1.在struts2中实现文件下载Action的返回值使用的是stream,这点可以从Struts2的文档中就可以看出:
[b][color=red]Stream Result Used to stream an InputStream back to the browser (usually for file downloads) [/color][/b]
2.通过查看struts2.x的核心jar包中的struts-default.xml文件中,发现其中有一个名为stream的文件下载拦截器
<result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>
翻开这个类,就可以发现定义了四个变量:
...
protected String contentType="text/plain";//文件内容类型
protected String contentLength;//长度
protected String contentDisposition="inline";//默认方式为inline
protected String inputName="inputStream"; //inputStream的名称
protected String inputStream inputStream; //输入流,用于读取文件
protected int bufferSize=1024;//设置缓冲区大小
...
透过此类不难发现,其实Struts2实现文件下载的本质与普通Servlet是一致的,只是Struts2通过拦截器和配置文件进行工作。在下载Action的方法中有个固定的写法就是:
public InputStream getDownloadFile(){
//....
//编写返回InputStream的方法,可以直接用FileInputStream读取文件,也可以用其他方式
}
这个方法只要求返回要下载的文件的InputStream即可。所以,我也可以这样实现
public InputStream getDownloadFile() {
String fileName = "";
String pathName = ServletActionContext.getServletContext().getRealPath("/upload");
String fullName = "";
InputStream in =null;
try {
fileName = new String(request.getParameter("filename").getBytes(
"ISO-8859-1"), "GB2312");// 获取文件名,并且进行转码,防止乱码
System.out.println(fileName);
System.out.println(pathName);
fullName=pathName+"\\"+fileName;//完整的文件名
System.out.println(fullName);
in =new FileInputStream(fullName);
} catch (Exception e) {
e.printStackTrace();
}
// return ServletActionContext.getServletContext().getResourceAsStream(
// "/upload/" + fileName);
return in;
}
其实这个InputStream就如同使用Servlet实现下载时,获取到的InputStream,它是就是用来读取要下载的文件的,按照此逻辑应该有OutputStream才对,似乎没有发现。[color=red][b]翻看StreamResult类,发现它的doExecute(...)方法,就可以发现此方法都是对HTTP请求头content-Disposition以及response.getOutputStream的操作[/b][/color](翻翻源码对自己是有好处滴~)
至此可以看见Struts2框架实现文件下载其实原理和Servlet文件下载的方式是一致的,也就完全理解了Struts2实现文件下载为什么要配置相应的参数了
附上关于配置文件中参数的解释,免得以后自己忘记:
[color=blue]contentType - the stream mime-type as sent to the web browser (default = text/plain).
contentLength - the stream length in bytes (the browser displays a progress bar).
contentDisposition - the content disposition header value for specifing the file name (default = inline, values are typically attachment;filename="document.pdf".
inputName - the name of the InputStream property from the chained action (default = inputStream).
bufferSize - the size of the buffer to copy from input to output (default = 1024).
allowCaching - if set to 'false' it will set the headers 'Pragma' and 'Cache-Control' to 'no-cahce', and prevent client from caching the content. (default = true)
contentCharSet - if set to a string, ';charset=value' will be added to the content-type header, where value is the string set. If set to an expression, the result of evaluating the expression will be used. If not set, then no charset will be set on the header [/color]