文件下载的核心思想即是将文件从一个地方拷贝到另一个地方.

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源码,其对应参数,看过源码后就会发现其实下载和传统方式差不多,就是将其优化了不少.

posted on 2017-10-11 16:39  帅哥的爸爸  阅读(193)  评论(0编辑  收藏  举报