文件下载的核心思想即是将文件从一个地方拷贝到另一个地方.
1.传统方式:
在Action中加入大量servlet api 操作.优点是好理解,缺点是耦合度高。
2.stream方式:
使用struts2中的stream拦截器进行操作
二.实例:
我这里用的是maven,贴出pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.amos</groupId>
<artifactId>struts2_learn</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>struts2_learn Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.3.16</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.1.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
<build>
<finalName>struts2_learn</finalName>
</build>
</project>
1.使用传统方式实现文件下载:
DownloadAction.java
package download;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
/**
* @ClassName: DownloadAction
* @Description: 文件下载
* @author: amosli
* @email:amosli@infomorrow.com
* @date Feb 13, 2014 1:22:23 AM
*/
public class DownloadAction extends ActionSupport {
private static final long serialVersionUID = -5609061774548242181L;
private String fileName;//文件名称
public void setFileName(String fileName) {
if (ServletActionContext.getRequest().getMethod().equals("GET")) {
try {
byte[] bytes = fileName.getBytes("ISO8859-1");//将get方式提交的中文进行处理,即将编码由ISO8859-1转为utf-8
fileName = new String(bytes, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
this.fileName = fileName;
}
// 下载
public String execute() throws Exception {
// 1.传统下载方式
// 取得HttpServletResponse对象
HttpServletResponse response = ServletActionContext.getResponse();
// 取得ServletContext对象
ServletContext context = ServletActionContext.getServletContext();
// 通知浏览器以下载方式打开文件
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
// 取得需要下载文件的根目录
String realPath = context.getRealPath("/WEB-INF/download");
// 构造子节输入流
InputStream is = new FileInputStream(realPath + "/" + fileName);
// 构造子节输出流
OutputStream os = response.getOutputStream();
byte[] b = new byte[1024];
int len = 0;
while ((len = is.read(b)) > 0) {
os.write(b, 0, len);
}
is.close();
os.close();
return null;
}
}
download.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
英文需要编码
<a href="/struts2_learn/DownloadAction?fileName=building.jpg"
style="text-decoration: none">
building.jpg
</a> <hr>
<%-- <c:url var="myURL" value="/DownloadAction">
<c:param name="fileName" value="建筑.jpg" />
</c:url>
<a href="${myURL}" style="text-decoration: none"> 建筑.jpg </a> --%>
</body>
</html>
download_struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package name="download" extends="struts-default">
<action name="DownloadAction" class="download.DownloadAction" method="execute">
</action>
</package>
</struts>
struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!--<include file="config/upload.xml"></include> -->
<!-- 加载其他配置文件 -->
<!-- <include file="config/upload-interceptor.xml"></include> -->
<!-- 加载属性文件-国际化 -->
<!-- <constant name="struts.custom.i18n.resources" value="message"></constant> --> <!-- 结果集 -->
<!-- <include file="config/result_struts.xml"></include> -->
<!-- 类型转换 -->
<!-- <include file="config/type_struts.xml"></include> -->
<!-- 文件下载 -->
<include file="config/download_struts.xml"></include>
</struts>
效果如下图所示,点击building.jpg即可开始下载:

代码运行顺序:
首先,项目启动,加载struts.xml--->download_struts.xml-->将对应的DownloadAction加载.
其次,用户访问download.jsp页面,点击超链接,即开始调用DownloadAction进行下载.
核心程序即为DownloadAction.java,将要下载的文件写入到输入流,FileInputStream,然后再将文件从输入流写入到输出流,即将文件从一个地方拷贝到另一个地方.HttpServletResponse,将文件回写给浏览器,以达到下载文件的目的.
最后,文件成功下载,文件被拷贝到指定的地方.
这里要注意的是如果是GET请求方式,那么要注意中文乱码的问题,这里涉及到转码的问题,要做一个判断,详情可参考上面的代码.
2.使用stream方式进行文件下载:
DownloadStreamAction.java
package download;
import java.io.InputStream;
import java.net.URLEncoder;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
/**
* @ClassName: DownloadStreamAction
* @Description: 现代下载方式
* @author: amosli
* @email:amosli@infomorrow.com
* @date Feb 13, 2014 12:35:26 AM
*/
public class DownloadStreamAction extends ActionSupport {
private static final long serialVersionUID = -2747191035343710583L;
private String fileName;
public void setFileName(String fileName) throws Exception {
if(ServletActionContext.getRequest().getMethod().equals("GET")){
byte[] bytes = fileName.getBytes("ISO8859-1");
fileName=new String(bytes,"utf-8");
}
this.fileName = fileName;
}
public String getFileName() throws Exception {
return URLEncoder.encode(fileName, "utf-8");
}
public InputStream getImageStream() throws Exception {
InputStream inputStream = ServletActionContext.getServletContext().getResourceAsStream("/WEB-INF/download/"+fileName);
return inputStream;
}
}
download_struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!-- <package name="download" extends="struts-default">
<action name="DownloadAction" class="download.DownloadAction" method="execute">
</action>
</package> -->
<package name="download" extends="struts-default">
<action name="DownloadAction" class="download.DownloadStreamAction" method="execute">
<!-- 以stream二进制流的方式打开 -->
<result name="success" type="stream">
<!-- 指明文件的下载类型 -->
<param name="contentType">image/jpeg</param>
<!-- 指明如果取得需要下载文件的InputStream输入流 -->
<param name="inputName">imageStream</param>
<!-- 指明让浏览器以下载框的方式打开 -->
<param name="contentDisposition">attachment;filename="building.jpg"</param>
<!--<param name="contentDisposition">attachment;filename=${fileName}</param>-->
<!-- 指明下载文件时的字符数组byte[]大小 -->
<param name="bufferSize">1024</param>
</result>
</action>
</package>
</struts>
这里如果仅仅看DownloadStreamAction,会发现代码简洁明了,少了很多,再看download_struts.xml,会发现之前我们自己做的事,都被struts代替了,比如字符数组的大小,这里以参数配置的形式出现,方便了许多.
注意:imageStream要和DownloadStreamAction中的getImageStream相对应,不可写错.
关于其具体实现可以查看org.apache.struts2.dispatcher.StreamResult源码,其对应参数,看过源码后就会发现其实下载和传统方式差不多,就是将其优化了不少.
浙公网安备 33010602011771号