前言
上一篇文章总结了上传,说完上传,那就不得不说说下载了。说到下载,就要先看看《Struts2学习之结果类型总结》这篇文章中总结的结果类型了。
Struts2提供了stream结果类型,该结果类型就是专门用于支持文件下载功能的。指定stream结果类型时,需要指定一个inputName参数,该参数指定了一个输入流,这个输入流是被下载文件的入口。通过Struts2的文件下载支持,允许系统控制浏览者下载文件的权限。
实现文件下载的Action
实现文件的下载,思路无非都是这样的:
Request->File->Stream->Response
有了这样的思路,我们就知道,我们最终要给客户端返回一个Stream。那么我们在服务器的主要任务就是生成这个Stream。具体的代码如下:
public class DownloadAction extends ActionSupport
{
private String fileName;
public void setFileName(String fileName)
{
this.fileName = fileName;
}
public String getFileName()
{
return this.fileName;
}
public InputStream getTargetFile() throws Exception
{
// 这里返回Stream
return ServletActionContext.getServletContext().getResourceAsStream("/images/" + fileName);
}
public String execute() throws Exception
{
return SUCCESS;
}
}
配置Action
Struts2是以配置为主的框架。对此,在开发一个下载模块的时候,最重要的任务还是配置。主要涉及以下几个配置项的配置:
- contentType – 指定被下载文件的类型,默认为text/plain
- contentLength – 指定被下载文件的大小,浏览器根据这个来显示一个下载进度条
- contentDisposition – 指定下载的文件名
- inputName – 指定下载文件的入口输入流,默认为inputStream
- bufferSize – 指定下载文件时的缓冲大小,默认为1024字节
对应的,我们的配置文件写法如下:
<package name="download" extends="struts-default">
<action name="download" class="com.jellythink.practise.DownloadAction">
<result name="success" type="stream">
<param name="contentType">image/png</param>
<param name="inputName">targetFile</param>
<param name="contentDisposition">attachment;filename="${fileName}"</param>
<param name="bufferSize">4096</param>
</result>
</action>
</package>
到此,我们在浏览器中输入:http://localhost:8080/Struts2DownloadDemo/download?fileName=struts2result.png就可以进行下载测试了。
为什么不用指定“contentLength”?
我们实现下载功能时,基本上都会指定下载文件的大小,好让浏览器知道我们下载文件的大小,从而正确的显示进度条等信息。然而,上面的配置中,我并没有指定contentLength
参数,这是为什么?
当我们进行配置时,如果没有没有指定contentLength
参数,这里就涉及到另一个协议——HTTP TRUNKED协议。该协议当content-Length未指定的时候,会对数据进行分片传输,并以0结尾,标示文件传输结束。同时,当文件大小不可知或未能明确给出时,会在http的响应报文中,给出Transfer-Encoding chunked字段;同时content-Length与Transfer-Encoding:chunked只能存在其一。
总结
我们在开发的过程中,经常会实现下载的功能,比如验证码,这个也需要下载功能。我们需要更多的实战去掌握这些知识点。
果冻想,认真玩技术的地方。
2016年5月5日 于呼和浩特。