文件下载

一、原理

1.单文件下载
(1)找出文件在Web应用的虚拟路径。 如 "WEB-INF/data/1.jpg"。
(2)根据虚拟路径,查找出该文件在服务器硬盘中的物理地址。
(3)读入输入流。
(4)设置响应类型,为固定格式:
resp.setContentType("applicaton/x-msdownload");
(*5)需要对文件名进行编码,因为中文下会出现乱码:
fileName = URLEncoder.encode(fileName, "UTF-8");
(6)设置响应头Content-Disposition:
resp.setHeader("Content-Disposition", "attachment;filename="+fileName);
(7)以响应输出流的方式返回响应。
(8)关闭两个流。

示例代码:

String filePath = "/WEB-INF/data/" + fileName;
String realPath = getServletContext().getRealPath(filePath);
InputStream is = new FileInputStream(realPath);
resp.setContentType("applicaton/x-msdownload");
fileName = URLEncoder.encode(fileName, "UTF-8");
resp.setHeader("Content-Disposition", "attachment;filename="+fileName);

ServletOutputStream os = resp.getOutputStream();
byte[] b = new byte[1024];
int len = 0;

while((len = is.read(b)) != -1) {
os.write(b, 0, len);
}
is.close();
os.close();

说明:
通过 a 标签的 href 指向资源位置,也可以提供下载,但是存在一个问题,若下载的文件是浏览器本身可以解析的话,浏览器会打开,而不会下载。

2.多文件打包下载:
与单文件下载的区别:
(1)设置响应类型:
resp.setContentType("Content-type: text/zip");
(2)设置响应头:
resp.setHeader("Content-Disposition", "attachment; filename=mytest.zip");
(3)使用 ZipOutputStream 对 ServletOutputStream 进行包装。
(4)遍历每一个要下载的文件,为每个文件创建对应的Entry然后放入 ZipOutputStream 中。
(5)读取该文件,然后以 ZipOutputStream 的形式写出。

示例代码:

String filePathBase = "/WEB-INF/data/";
String filePath = filePathBase + "1.jpg";
String filePath2 = filePathBase + "项目中出现的问题.txt";

List<File> files = new ArrayList<>();
files.add(new File(req.getSession().getServletContext().getRealPath(filePath)));
files.add(new File(req.getSession().getServletContext().getRealPath(filePath2)));

resp.setContentType("Content-type: text/zip");
resp.setHeader("Content-Disposition", "attachment; filename=mytest.zip");

ServletOutputStream os = resp.getOutputStream();
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(os));
for(File file : files) {
zos.putNextEntry(new ZipEntry(file.getName()));

InputStream fis = new FileInputStream(file);

BufferedInputStream bis = new BufferedInputStream(fis);

int data = 0;
while((data = fis.read()) != -1) {
zos.write(data);
}

bis.close();
zos.closeEntry();

}
zos.close();

二、Struts2

1.参考 Struts2 docs 中 Result Types → Stream Result。

<result name="success" type="stream">
  <param name="contentType">image/jpeg</param>
  <param name="inputName">inputStream</param>
  <param name="contentDisposition">attachment;filename="document.pdf"</param>
  <param name="bufferSize">1024</param>
</result>

2.以上属性可以在 Action 中以 getXxx() 方法提供。

3.需要注意下载文件若为中文,需要对其进行 "UTF-8" 编码

4.例子:

<s:a value="/downLoad">点我</s:a>
form
<action name="downLoad" class="com.nucsoft.download.DownLoadAction">
            <result name="success" type="stream">
                <param name="contentType">text/xml</param>
                <param name="inputName">inputStream</param>
                <!--<param name="contentDisposition">attachment;filename="你好.xml"</param>-->
            </result>
</action>
struts.xml
/**
 * @author solverpeng
 * @create 2016-07-12-20:04
 */
public class DownLoadAction extends ActionSupport{
    private InputStream inputStream;

    public InputStream getInputStream() {
        return inputStream;
    }

    public String contentDisposition;

    public String getContentDisposition() throws UnsupportedEncodingException {
        String fileName = URLEncoder.encode("你好.xml", "UTF-8");
        String contentDisposition = "attachment;filename=""+fileName+""";
        return contentDisposition;
    }

    @Override
    public String execute() throws Exception {
        String realPath = ServletActionContext.getServletContext().getRealPath("/WEB-INF/你好.xml");
        inputStream = new FileInputStream(realPath);
        return SUCCESS;
    }
}
DownLoadAction

未完,待续。

原文地址:https://www.cnblogs.com/solverpeng/p/5613738.html