本来下载文件这事,我还想自己写个方法去实现的。但是想到项目使用到了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实现文件下载功能,可以直接运行!
Struts2下载文件时中文乱码和空格处理
在struts2基础上实现的包括单文件、多文件的上传及下载
struts2中的文件上传和下载: 1.首先导入commons-fileupload-1.2.1.jar和commons-io-1.4.jar两个jar包 2.其次JSP页面中的文件上传控件所在的form必须设置属性enctype="multipart/form-data" 3.再次,struts2中...
Struts2 下载文件不同浏览器兼容问题,实现不同浏览器下载文件名是action名的问题
struts2中实现文件上传 struts2中实现CRUD struts2中的OGNL struts2的新表单标志的使用 struts2与AJAX一 struts2与AJAX二 struts2与AJAX三 struts2中用Spring实现IOC struts2中的零配置与IOC struts2介绍之使用连接...
Struts2 Struts2 超好的Struts2 pdf 文档 Struts2 Struts2 超好的Struts2 pdf 文档 Struts2.pdf文档
网上很多有关struts2的api文档都是不全的。我经过精心整理出的struts2api文档,非常齐全。
在我们做struts2文件下载的时候,经常会遇到这种问题:点“打开/保存”一切正常,但当我们点击“取消”时,却报一堆的异常(其中包括ClientAbortException异常),非常让人头疼,如何彻底解决呢?附件中使用struts2-...
struts2配置文件以及代码示例struts2配置文件以及代码示例struts2配置文件以及代码示例struts2配置文件以及代码示例struts2配置文件以及代码示例struts2配置文件以及代码示例struts2配置文件以及代码示例struts2配置...
struts2的根本webwork2
在struts官网下的struts2中没有帮助文档,几经周折找到的API文档,包括了struts中常用jar包(struts2-core,xwork-core等)!
struts2文件上传和下载 struts2文件上传和下载 struts2文件上传和下载 struts2文件上传和下载 struts2文件上传和下载
Struts2的开发文档,学习Struts2时可以用来查阅API相关接口说明,便于分析框架原理
struts2文件下载极其简单struts2文件下载极其简单struts2文件下载极其简单struts2文件下载极其简单
Struts2 开发者文档 api
使用struts2框架进行文件的上传并限制文件的大小与类型,使用struts2框架实现文件下载
Struts2 api文档