众所周知,在struts.xml中,每个action元素内,可以有一个或多个的result子元素,然后我们可以通过在Action类的execute方法的返回值与result元素的name属性进行匹配,然后找到对应的物理视图,实际上result元素除了name属性以外,还有type属性,由于不同的type属性,struts2会调用不同的处理类来处理请求和响应,因此可以通过指定不同的类型来指定struts2架构以不同的动作、方式进行请求、响应处理,先来看看struts-default.xml里面的result片段;
<result-types> <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/> <result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/> <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/> <result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/> <result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/> <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/> <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/> <result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/> <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/> <result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" /> <result-type name="postback" class="org.apache.struts2.dispatcher.PostbackResult" /> </result-types>通过上述片段,我们可以知道,struts2默认以请求转发的方式响应客户请求;这时候,大家注意到我们的下载不也正是需要在响应的时候需要以流的方式处理嘛,针对下载这一点,struts2专门提供了一个stream的结果类型来专门处理下载;
由于stream结果类型的处理类是ora.apache.struts2.dispatcher.StreamResult,咱们先来看一下这个类内部有哪些参数以及每个参数的作用
contentType | String | 用来指定发送到web浏览器的流的MIME类型 |
contentLength | String | 流的长度,以比特位单位(浏览器展示下载进度条) |
contentDisposition | String | 用来指定文件名称以及客户端打开文件的方式(默认是用内嵌方式打开,一般来说可以指定attachment;filename="document.pdf") |
inputName | String | 用来指定Action链中,InputStream属性名,需要记住的是这个属性是用来作为文件下载的流的来源,默认值为inputStream |
bufferSize | 用来指定从输入到输出中,缓冲区的大小 | |
allowCaching | boolean | 如果将它设为false,它会将响应头的pragma和cache-control的content属性设置为no-cache来阻止客户端缓存内容,默认值为true |
contentCharSet | String | 如果给这个属性设置一个字符串,那么‘;charset=value’将会被添加到响应头的content-type中 |
好的,来看配置
package com.struts2.controller; import java.io.File; import java.io.InputStream; import javax.servlet.ServletContext; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class FileDownloadAction extends ActionSupport { // 文件的Mime类型 private String contentType; // 文件的放置路径 private String filePath; // 要下载的文件名称 private String fileName; // 该属性设置与否都可以,但是比如提供get方法 private InputStream fileInputStream; public InputStream getFileInputStream() { // 以及文件的mime类型以及创建流 ServletContext context = ServletActionContext.getServletContext(); String mimeType = context.getMimeType(context.getRealPath(filePath + "/" + fileName)); setContentType(mimeType); return context.getResourceAsStream(filePath + "/" + fileName); } public void setFileName(String fileName) { this.fileName = fileName; } public String getFileName() { return fileName; } public void setFileInputStream(InputStream fileInputStream) { this.fileInputStream = fileInputStream; } public String getContentType() { return contentType; } public void setContentType(String contentType) { this.contentType = contentType; } public String getFilePath() { return filePath; } public void setFilePath(String filePath) { this.filePath = filePath; } }struts.xml中的配置如下:
<!-- 处理文件的下载请求 --> <action name="download" class="com.struts2.controller.FileDownloadAction"> <!-- 服务器端待下载文件的路径 --> <param name="filePath">/0810</param> <!-- 处理文件下载时,一定要将返回result的类型设置为stream --> <result name="success" type="stream"> <!-- 指定下载文件的MIME类型 --> <param name="contentType">${contentType}</param> <!-- 指定有当前Action 中的哪个方法返回数据流 --> <param name="inputName">fileInputStream</param> <!-- 指定文件下载时,浏览器处理文件的方式 --> <param name="contentDisposition">attachment;filename="${fileName}"</param> </result> </action>需要在WebRoot下面新建一个0810的文件夹,里面放置若干文件,然后在浏览器地址栏输入:
http://localhost:8080/struts2/download?fileName=0810文件夹的任意文件名,就可以实现一个简单下载了;
Struts2的下载机制并不复杂,关键点在于对Struts2处理文件下载时的思路,以及对于StreamResult的理解,搞清楚前因后果,思想理解好了,就没有什么太大问题!