`
laotu5i0
  • 浏览: 141008 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

理解和灵活应用 Struts2 的文件下载功能

    博客分类:
  • java
阅读更多

文件下载给我们最直接的概念就是,给个文件链接点击就下载。似乎太简单,然而 Struts2 却把它作为一个独立的学问来对待,理由有四:

1. 文件名为中文时,直接点击下载,链接可能会走样(某些浏览器,URL 编码的问题),致使无法下载。
2. 不总是从下载实际的文件,文件内容有时候是动态生成的,如数据库中的内容。
3. 对于知名的文件类型不让浏览器直接打开,而是出现下载对话框保存文件。例如,要下载的文件是 .txt 的,可能直接就在浏览器中显示其内容。
4. 需要授权才能下载文件时

当然对于以上若干问题,Servlet/JSP 都能通过正确的 URL 编码,响应头设置、权限代码控制解决,只是 Struts2 让我们处理起来更方便了,内部原理自然是一样的。

先来看下 Servlet 如何实现文件下载的,直接见代码:

view source
<object id="highlighter_304590_clipboard" title="copy to clipboard" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="16" height="16" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" type="application/x-shockwave-flash"> <param name="_cx" value="423"> <param name="_cy" value="423"> <param name="FlashVars"> <param name="Movie" value="/Files/framework/clipboard.swf.zip"> <param name="Src" value="/Files/framework/clipboard.swf.zip"> <param name="WMode" value="Transparent"> <param name="Play" value="0"> <param name="Loop" value="-1"> <param name="Quality" value="High"> <param name="SAlign"> <param name="Menu" value="0"> <param name="Base"> <param name="AllowScriptAccess" value="always"> <param name="Scale" value="ShowAll"> <param name="DeviceFont" value="0"> <param name="EmbedMovie" value="0"> <param name="BGColor"> <param name="SWRemote"> <param name="MovieData"> <param name="SeamlessTabbing" value="1"> <param name="Profile" value="0"> <param name="ProfileAddress"> <param name="ProfilePort" value="0"> <param name="AllowNetworking" value="all"> <param name="AllowFullScreen" value="false"></object>
print?
01.PrintWriter out = response.getWriter();
02.  
03.//不管实际类型,待下载文件 ContentType 统一指定为 application/octet-stream
04.response.setContentType("application/octet-stream");
05.  
06.//中文文件名必须转码为 ISO8859-1,否则为乱码
07.String fileName = new String("文本文件.txt".getBytes(), "ISO8859-1");
08.  
09.//作为附件下载,相应的 "inline;filename = "+fileName 是在线(浏览器中显示内容)打开
10.response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
11.  
12.//因为文件编码也为 ISO8859-1,所以内容须转码成 ISO8859-1,尚不知如何控制下载文本文件的编码
13.//或有谁知道的,还请告诉我一下。 文件内容可以从物理文件中来,或者数据库中读取填入等等
14.out.write(new String("Servlet 文件下载测试".getBytes(), "ISO8859-1"));
15.  
16.out.close();


知道了上面各行的含义,再来看下 Struts2 的解决方式,其实不过是把某些代码的功能移入到了配置文件而已。在李刚所著的《Struts 2 权威指南》中说 Struts 实现文件下载是由一个 download 拦截器。其实不然,只是一个 StreamResult(org.apache.struts2.dispatcher.StreamResult) 而已,也不像实现文件上传那样要额外的 JAR 包。在 StreamResult 中有以下几个默认属性要留意一下:

    public static final String DEFAULT_PARAM = "inputName";

 

    protected String contentType = "text/plain";
    protected String contentDisposition = "inline";
    protected String inputName = "inputStream";
    protected InputStream inputStream;
    protected int bufferSize = 1024;

StreamResult 的实现细节敬请阅读它的源代码,实现过程一言以蔽之就是:从 inputStream 获取内容,以相应的 contentType、contentDisposition 和 bufferSize 输出给浏览器,对 contentType 和 contentDisposition 的相应设置就能实现文件下载,可对照前面 Servlet 的实现。看个实际的例子吧。

struts.xml 中 Action 的配置,假定 Action 类为 com.unmi.DownLoadAction

view source
<object id="highlighter_544051_clipboard" title="copy to clipboard" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="16" height="16" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" type="application/x-shockwave-flash"> <param name="_cx" value="423"> <param name="_cy" value="423"> <param name="FlashVars"> <param name="Movie" value="/Files/framework/clipboard.swf.zip"> <param name="Src" value="/Files/framework/clipboard.swf.zip"> <param name="WMode" value="Transparent"> <param name="Play" value="0"> <param name="Loop" value="-1"> <param name="Quality" value="High"> <param name="SAlign"> <param name="Menu" value="0"> <param name="Base"> <param name="AllowScriptAccess" value="always"> <param name="Scale" value="ShowAll"> <param name="DeviceFont" value="0"> <param name="EmbedMovie" value="0"> <param name="BGColor"> <param name="SWRemote"> <param name="MovieData"> <param name="SeamlessTabbing" value="1"> <param name="Profile" value="0"> <param name="ProfileAddress"> <param name="ProfilePort" value="0"> <param name="AllowNetworking" value="all"> <param name="AllowFullScreen" value="false"></object>
print?
01.<action name="download" class="com.unmi.action.DownloadAction">
02.    <result name="success" type="stream"><!--type 为 stream 应用 StreamResult 处理-->
03.        <param name="contentType">application/octet-stream</param><!--默认为 text/plain-->
04.          
05.        <!-- 默认就是 inputStream,它将会指示 StreamResult 通过 inputName 属性值的 getter 方法,
06.              比如这里就是 getInputStream() 来获取下载文件的内容,意味着你的 Action 要有这个方法 -->
07.        <param name="inputName">inputStream</param>
08.          
09.        <!-- 默认为 inline(在线打开),设置为 attachment 将会告诉浏览器下载该文件,filename 指定下载文
10.              件保有存时的文件名,若未指定将会是以浏览的页面名作为文件名,如以 download.action 作为文件名,
11.              这里使用的是动态文件名,${fileName}, 它将通过 Action 的 getFileName() 获得文件名 -->
12.        <param name="contentDisposition">attachment;filename="${fileName}"</param>
13.        <param name="bufferSize">4096</param><!-- 输出时缓冲区的大小 -->
14.    </result>


说明:对于上面的配置其他参数可以用默认值,关键就是 contentDisposition 要设置为 attachment 才能提示下载,同时用 filename 指定文件名,若直接指定非动态的文件名。

DownloadAction 代码,需要实现 getInputStream() 返回输入流;因前面用的动态文件名,所以须加上 getFileName() 返回文件名,若非动态文件名,则该方法可省去。

view source
<object id="highlighter_542863_clipboard" title="copy to clipboard" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="16" height="16" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" type="application/x-shockwave-flash"> <param name="_cx" value="423"> <param name="_cy" value="423"> <param name="FlashVars"> <param name="Movie" value="/Files/framework/clipboard.swf.zip"> <param name="Src" value="/Files/framework/clipboard.swf.zip"> <param name="WMode" value="Transparent"> <param name="Play" value="0"> <param name="Loop" value="-1"> <param name="Quality" value="High"> <param name="SAlign"> <param name="Menu" value="0"> <param name="Base"> <param name="AllowScriptAccess" value="always"> <param name="Scale" value="ShowAll"> <param name="DeviceFont" value="0"> <param name="EmbedMovie" value="0"> <param name="BGColor"> <param name="SWRemote"> <param name="MovieData"> <param name="SeamlessTabbing" value="1"> <param name="Profile" value="0"> <param name="ProfileAddress"> <param name="ProfilePort" value="0"> <param name="AllowNetworking" value="all"> <param name="AllowFullScreen" value="false"></object>
print?
01.package com.unmi.action;
02.  
03.import java.io.*;
04.import java.text.*;
05.import java.util.Date;
06.  
07./**
08. * 文件下载的 Action 
09. * @author Unmi
10. */
11.public class NetbookSerialAction {
12.  
13.    public String execute() throws Exception {
14.        //这里可加入权限控制
15.        return "success";
16.    }
17.  
18.    //获得下载文件的内容,可以直接读入一个物理文件或从数据库中获取内容
19.    public InputStream getInputStream() throws Exception {
20.        //return new FileInputStream("somefile.rar"); 直接下载 somefile.rar
21.  
22.        //和 Servlet 中不一样,这里我们不需对输出的中文转码为 ISO8859-1
23.        return new ByteArrayInputStream("Struts2 文件下载测试".getBytes());
24.    }
25.  
26.    //对于配置中的 ${fileName}, 获得下载保存时的文件名
27.    public String getFileName() {
28.        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
29.        String fileName = "序列号(" + df.format(new Date()) + ").txt";
30.        try {
31.            //中文文件名也是需要转码为 ISO8859-1,否则乱码
32.            return new String(fileName.getBytes(), "ISO8859-1");
33.        } catch (UnsupportedEncodingException e) {
34.            return "impossible.txt";
35.        }
36.    }
37.}



谨记一个就是,要想下载的文件名不乱码就要以 ISO8859-1 字符集进行转码,内容会否乱码可在调试中解决。

好啦,启动服务,访问 http://localhost:8080/teststruts2/download.action,浏览器便会提示下载 序列号(2009-06-17).txt,内容为:“Struts2 文件下载测试”。

 

分享到:
评论

相关推荐

    源码基于JSP的博客系统(struts+hibernate+spring).rar

    它包含用于构建一个功能齐全的博客系统的源代码和资源文件,结合了Java Server Pages (JSP)、Apache Struts框架、Hibernate持久化框架以及Spring框架的强大功能,以支持高效的数据库操作和灵活的业务逻辑处理。...

    Struts原理、开发及项目实施

    Struts原理、开发及项目实施 Holen 2002-9-12 &lt;br/&gt;1、 摘要 2、 关键词 3、 Framework 4、 Struts的起源 5、 Struts工作原理 6、 Struts安装 7、 一个实例 8、 Struts优缺点...

    ExtJS Web应用程序开发指南(1-10)

    ·与主流技术的整合应用——考虑到ExtJS开发的实际情况,本书还特意讲解与Ajax、JSP标签库、Struts的整合,真正实现在开发中灵活应用ExtJS。 精彩示范效果 包含相关实例文件,源代码和ExtJS库文件。...

    ExtJS Web应用程序开发指南(10-15)完毕

    ·与主流技术的整合应用——考虑到ExtJS开发的实际情况,本书还特意讲解与Ajax、JSP标签库、Struts的整合,真正实现在开发中灵活应用ExtJS。 精彩示范效果 包含相关实例文件,源代码和ExtJS库文件。...

    外文翻译 stus MVC

    Struts is a set of cooperating classes, servlets, and JSP tags that make up a reusable MVC 2 design. This definition implies that Struts is a framework, rather than a library, but Struts also contains...

    JAVA上百实例源码以及开源项目

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    Spring面试题

    理解控制反转最简单的方式就是看它的实际应用。在对由三部分组成的 Spring 系列 的第 1 部分进行总结时,我使用了一个示例,演示了如何通过 Spring IOC 容器注入应用程序的依赖关系(而不是将它们构建进来)。 我用...

    2023Java的学习

    Java的高级特性包括异常处理、多线程、文件和输入输出流、网络编程、反射、泛型、集合、枚举、并发编程等内容。这些内容是Java语言的高级特性,可以帮助程序员提高程序的性能和稳定性,是实现复杂程序的关键。 Java...

    java开源包2

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包10

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    JAVA上百实例源码以及开源项目源代码

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    iuhyiuhkjh908u0980

    例如,可以使用j2mepolish,请参考本人以前发表的文章《使用J2mePolish的build和preprocess功能》。本文主要讨论如何使用antenna来解决这个问题。 Antenna介绍 Ant ... by pandonix 2007-08-28 回复 (9) 用Ant 来...

    java开源包1

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包11

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包3

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包6

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包5

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包4

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包8

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

Global site tag (gtag.js) - Google Analytics