`
Rainbow702
  • 浏览: 1078180 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
阅读更多

本来下载文件这事,我还想自己写个方法去实现的。但是想到项目使用到了struts2框架,而struts2中的“StreamResult”这个result恰好就是用来下载的,所以,何必自再写呢。呵呵。

 

首先,我们看一下“org.apache.struts2.dispatcher.StreamResult”类的JAVADOC,如下:

 

A custom Result type for sending raw data (via an InputStream) directly to the HttpServletResponse. Very useful for allowing users to download content. 

This result type takes the following parameters: 

★  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 

These parameters can also be set by exposing a similarly named getter method on your Action. For example, you can provide getContentType() to override that parameter for the current action.

根据doc来配置我们的result。如下:

@Result(name = "dlManual", type = "stream", params = { "contentType", "application/msword", "contentDisposition", "attachment;fileName=\"${manualName}\"", "inputName", "manualInputStream", "bufferSize", "2048" }) })

  对于上面的Result的写法不明白的话,可以参照我的另一篇BLOG(param 中的参数下面会有说明):

http://rainbow702.iteye.com/blog/2218653

 

假设页面链接如下:

<a href="<%=request.getContextPath()%>/user!dlManual">download</a>

那么,我们在UserAction中,须存在一个名为 dlManual() 的方法,其如下:

public String dlManual() {
    LOG.debug("dlManual() start.");
    try {
        InputStream is = request.getServletContext().getResourceAsStream("/xxxx/xxxxxx.doc");
        this.setManualInputStream(is);
    } catch (Exception e) {
        LOG.error(e.getMessage(), e);
    } finally {
        LOG.debug("dlManual() end.");
    }
    return "dlManual";
}

上面有一点需要注意的是: 使用 getResourceAsStream() 去加载文件,传给它的路径须以“/”开头。

 

这个时候,我们在看一眼上面定义好的Result,其中它的“inputName”的值为“manualInputStream”,这样一来,我们须在action类中定义一个名为 manualInputStream 的InputStream字段。同时声明它的getter/setter方法。

private InputStream manualInputStream;
//getter
//setter

 另外,Result中的“contentDisposition”的值被声明为“attachment;fileName=\"${manualName}\"”,重点是“${manualName}”,它会被当作ONGL表达式进行解析,并在当前action中寻找一个名为manualName的字段(实际上是寻找名为  getManualName() 的方法,  这一点对于会反射的人应该理解起来没有问题)。

所以,我们需要声明一个 getManualName() 方法(当然你也可以声明一个 String类型的名称为 manualName 的字段,并声明它的getter方法)。

public String getManualName() {
    LOG.debug("getManualName() start.");
    String manualName = "xxxxx.doc";
    try {
        // the " " will be encoded as "+",
        // and IE will treat this "+" as a literal string, not the original " ", so here we replace "+" with "%20",
        manualName = URLEncoder.encode(manualName, Const.ENCODING_UTF8).replaceAll("\\+", "%20");
    } catch (UnsupportedEncodingException e) {
        LOG.error(e.getMessage(), e);
    }
    LOG.debug("getManualName() start, manualName: " + manualName);
    return manualName;
}

 以上有一处需要注意:需要使用URLEncoder对文件名进行encode,不然的话,中文会有问题。

另外,encode 会把空格解析成 “+”,而IE不会被这个“+”还原为初始的空格,所以我们要手动将“+”替换为“%20”。

 

OK,只需要如上来做就可以进行下载文件了。

测试环境 :

Chrome40

IE10

360 版本7.1 内核 31.1

 

 

 

以下附上 StreamResult 的关键代码,其实就跟我们自己写的下载文件的代码是一样的:

protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {

        // Override any parameters using values on the stack
        resolveParamsFromStack(invocation.getStack(), invocation);

        OutputStream oOutput = null;

        try {
            if (inputStream == null) {
                // Find the inputstream from the invocation variable stack
                inputStream = (InputStream) invocation.getStack().findValue(conditionalParse(inputName, invocation));
            }

            if (inputStream == null) {
                String msg = ("Can not find a java.io.InputStream with the name [" + inputName + "] in the invocation stack. " +
                    "Check the <param name=\"inputName\"> tag specified for this action.");
                LOG.error(msg);
                throw new IllegalArgumentException(msg);
            }

            // Find the Response in context
            HttpServletResponse oResponse = (HttpServletResponse) invocation.getInvocationContext().get(HTTP_RESPONSE);

            // Set the content type
            if (contentCharSet != null && ! contentCharSet.equals("")) {
                oResponse.setContentType(conditionalParse(contentType, invocation)+";charset="+contentCharSet);
            }
            else {
                oResponse.setContentType(conditionalParse(contentType, invocation));
            }

            // Set the content length
            if (contentLength != null) {
                String _contentLength = conditionalParse(contentLength, invocation);
                int _contentLengthAsInt = -1;
                try {
                    _contentLengthAsInt = Integer.parseInt(_contentLength);
                    if (_contentLengthAsInt >= 0) {
                        oResponse.setContentLength(_contentLengthAsInt);
                    }
                }
                catch(NumberFormatException e) {
                    if (LOG.isWarnEnabled()) {
                	LOG.warn("failed to recongnize "+_contentLength+" as a number, contentLength header will not be set", e);
                    }
                }
            }

            // Set the content-disposition
            if (contentDisposition != null) {
                oResponse.addHeader("Content-Disposition", conditionalParse(contentDisposition, invocation));
            }

            // Set the cache control headers if neccessary
            if (!allowCaching) {
                oResponse.addHeader("Pragma", "no-cache");
                oResponse.addHeader("Cache-Control", "no-cache");
            }

            // Get the outputstream
            oOutput = oResponse.getOutputStream();

            if (LOG.isDebugEnabled()) {
                LOG.debug("Streaming result [" + inputName + "] type=[" + contentType + "] length=[" + contentLength +
                    "] content-disposition=[" + contentDisposition + "] charset=[" + contentCharSet + "]");
            }

            // Copy input to output
            if (LOG.isDebugEnabled()) {
        	LOG.debug("Streaming to output buffer +++ START +++");
            }
            byte[] oBuff = new byte[bufferSize];
            int iSize;
            while (-1 != (iSize = inputStream.read(oBuff))) {
                oOutput.write(oBuff, 0, iSize);
            }
            if (LOG.isDebugEnabled()) {
        	LOG.debug("Streaming to output buffer +++ END +++");
            }
            
            // Flush
            oOutput.flush();
        }
        finally {
            if (inputStream != null) inputStream.close();
            if (oOutput != null) oOutput.close();
        }
    }

 

分享到:
评论

相关推荐

    struts2实现文件下载功能

    在这个“Struts2实现文件下载功能”的示例中,我们将深入探讨如何利用Struts2框架来实现在web应用中让用户下载文件的功能。 首先,我们需要理解文件下载的基本原理。在Web应用中,当用户点击一个链接或提交一个表单...

    struts2实现文件上传下载

    本篇文章将详细探讨如何在Struts2框架下实现文件的上传与下载。 首先,我们需要了解Struts2中的文件上传机制。Struts2提供了`FileUploadInterceptor`拦截器来处理文件上传请求。在处理文件上传时,开发者需要在...

    struts2文件上传下载源代码

    在Struts2中,文件上传和下载是常见的功能需求,特别是在处理用户交互和数据交换时。这篇博客文章提供的"struts2文件上传下载源代码"旨在帮助开发者理解和实现这些功能。 文件上传功能允许用户从他们的设备上传文件...

    struts2官方文档

    struts2官方文档

    struts2中文学习文档

    从给定的文件信息来看,标题“struts2中文学习文档”和描述“struts2的根本webwork2”表明这是一份关于Struts2框架的学习资料,特别强调了Struts2与WebWork2的关系。Struts2是Apache Struts的一个版本,它是一个用于...

    Struts2接口文档

    这个“Struts2接口文档”是开发者的重要参考资料,提供了关于Struts2框架内各个组件、类库以及接口的详细说明,帮助开发者深入理解框架的内部工作原理并有效地使用其功能。 Struts2的核心组件包括Action、Result、...

    struts2帮助文档

    struts2中实现文件上传 struts2中实现CRUD struts2中的OGNL struts2的新表单标志的使用 struts2与AJAX一 struts2与AJAX二 struts2与AJAX三 struts2中用Spring实现IOC struts2中的零配置与IOC struts2介绍之使用连接...

    struts2 API帮助文档

    这个API帮助文档是开发者在使用Struts2框架时的重要参考资料,它详细阐述了框架的各种组件、类库和方法,有助于理解并有效利用Struts2的功能。 1. **Struts2核心组件** - `struts2-core`:这是Struts2框架的核心...

    Struts2 Struts2 超好的Struts2 pdf 文档

    4. **结果类型(Result Types)**:Struts2支持多种结果类型,如`dispatcher`(默认,将结果转发到JSP页面)、`stream`(用于文件下载)、`redirect`(重定向URL)等,可以根据不同的需求选择合适的结果类型。...

    struts2_uploadify带进度条的多文件上传下载

    总之,这个项目实例为使用Struts2和Uploadify实现带进度条的多文件上传及下载功能提供了一个基础模板,对于学习和实践此类功能的开发者来说是一个有价值的参考。通过深入研究和理解这个项目的代码,可以提升对Struts...

    struts2所有jar包程序文件

    在下载并解压"struts2所有jar包"后,开发者需要将lib目录下的所有jar文件添加到项目构建路径中,确保运行时可以找到所有依赖。对于Maven或Gradle用户,可以通过在pom.xml或build.gradle文件中指定相应的依赖项,实现...

    Struts的文件下载

    在Struts中实现文件下载是一项常见的功能,尤其在处理用户请求获取服务器上的静态或动态资源时。这篇博文将深入探讨如何在Struts框架下实现文件下载的功能。 首先,我们需要了解文件下载的基本原理。当用户点击下载...

    struts2api文档(全)

    网上很多有关struts2的api文档都是不全的。我经过精心整理出的struts2api文档,非常齐全。

    Struts2之struts2文件下载详解案例struts012

    在Struts2中处理文件下载是常见的需求,比如用户请求下载服务器上的文件,如PDF、图片或其他类型的文档。本案例"Struts2之struts012"将深入探讨如何在Struts2中实现文件下载的功能。 首先,我们需要创建一个Action...

    Struts2下载文件点击取消出现的异常解决办法(含demo)

    在我们做struts2文件下载的时候,经常会遇到这种问题:点“打开/保存”一切正常,但当我们点击“取消”时,却报一堆的异常(其中包括ClientAbortException异常),非常让人头疼,如何彻底解决呢?附件中使用struts2-...

    Struts2帮助文档

    "Struts2.0中文教程.chm"文件很可能是官方文档的中文版,它将涵盖Struts2的基础概念、配置、控制器、模型、视图、拦截器、异常处理、国际化、测试等方面的内容。这份文档将帮助初学者快速上手,同时也为有经验的...

    Struts2+Jquery+Ajax

    "struts2 jar"文件包含了Struts2框架的核心库,可能包括struts2-core、struts2-convention、struts2-json-plugin等依赖,这些是开发Struts2应用必不可少的组件。 "Struts2"可能是项目实例代码,包括Action类、视图...

    Struts2文件流方式导出下载excel、Txt、image图片

    通过上述步骤,我们就可以在Struts2框架下实现文件流方式的下载功能,无论是Excel、TXT还是图片,都能有效地直接返回给浏览器,让客户端进行下载。这种方式既节省了服务器资源,也提高了用户体验。在实际项目中,...

    struts2文件上传下载

    在这个特定的项目中,我们关注的是"struts2文件上传下载"的功能,这涉及到用户通过Web界面上传文件到服务器,以及从服务器下载文件到用户的设备。 文件上传是Web应用中的常见需求,例如用户可能需要提交图片、文档...

Global site tag (gtag.js) - Google Analytics