文件下载的实现方法

实现文件下载有以下两种方法:

  • 通过超链接实现下载。
  • 利用程序编码实现下载。

通过超链接实现下载固然简单,但暴露了下载文件的真实位置,并且只能下载存放在 Web 应用程序所在的目录下的文件。

利用程序编码实现下载可以增加安全访问控制,还可以从任意位置提供下载的数据,可以将文件存放到 Web 应用程序以外的目录中,也可以将文件保存到数据库中。

利用程序实现下载需要设置两个报头:

1)Web 服务器需要告诉浏览器其所输出内容的类型不是普通文本文件或 HTML 文件,而是一个要保存到本地的下载文件,这需要设置 Content-Type 的值为 application/x-msdownload。

2)Web 服务器希望浏览器不直接处理相应的实体内容,而是由用户选择将相应的实体内容保存到一个文件中,这需要设置 Content-Disposition 报头。

该报头指定了接收程序处理数据内容的方式,在 HTTP 应用中只有 attachment 是标准方式,attachment 表示要求用户干预。在 attachment 后面还可以指定 filename 参数,该参数是服务器建议浏览器将实体内容保存到文件中的文件名称。

设置报头的示例如下:
response.setHeader(“Content-Type”, “application/x-msdownload”);
response.setHeader(“Content-Disposition”, “attachment;filename=”+filename);

文件下载的过程

下面继续通过 springMVCDemo11 应用讲述利用程序实现下载的过程,要求从《Spring MVC单文件上传》上传文件的目录(workspace.metadata.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\springMVCDemo11\uploadfiles)中下载文件,具体开发步骤如下:

1)编写控制器类

首先编写控制器类 FileDownController,在该类中有 3 个方法,即 show、down 和 toUTF8String。其中,show 方法获取被下载的文件名称;down 方法执行下载功能;toUTF8String 方法是下载保存时中文文件名的字符编码转换方法。

FileDownController 类的代码如下:

  1. package controller;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.UnsupportedEncodingException;
  5. import java.util.ArrayList;
  6. import javax.servlet.ServletOutputStream;
  7. import javax.servlet.http.HttpServletRequest;
  8. import javax.servlet.http.HttpServletResponse;
  9. import org.apache.commons.logging.Log;
  10. import org.apache.commons.logging.LogFactory;
  11. import org.springframework.stereotype.Controller;
  12. import org.springframework.ui.Model;
  13. import org.springframework.web.bind.annotation.RequestMapping;
  14. import org.springframework.web.bind.annotation.RequestParam;
  15. @Controller
  16. public class FileDownController {
  17. // 得到一个用来记录日志的对象,在打印时标记打印的是哪个类的信息
  18. private static final Log logger = LogFactory
  19. .getLog(FileDownController.class);
  20. /**
  21. * 显示要下载的文件
  22. */
  23. @RequestMapping("showDownFiles")
  24. public String show(HttpServletRequest request, Model model) {
  25. // 从 workspace\.metadata\.plugins\org.eclipse.wst.server.core\
  26. // tmp0\wtpwebapps\springMVCDemo11\下载
  27. String realpath = request.getServletContext()
  28. .getRealPath("uploadfiles");
  29. File dir = new File(realpath);
  30. File files[] = dir.listFiles();
  31. // 获取该目录下的所有文件名
  32. ArrayList<String> fileName = new ArrayList<String>();
  33. for (int i = 0; i < files.length; i++) {
  34. fileName.add(files[i].getName());
  35. }
  36. model.addAttribute("files", fileName);
  37. return "showDownFiles";
  38. }
  39. /**
  40. * 执行下载
  41. */
  42. @RequestMapping("down")
  43. public String down(@RequestParam String filename,
  44. HttpServletRequest request, HttpServletResponse response) {
  45. String aFilePath = null; // 要下载的文件路径
  46. FileInputStream in = null; // 输入流
  47. ServletOutputStream out = null; // 输出流
  48. try {
  49. // 从workspace\.metadata\.plugins\org.eclipse.wst.server.core\
  50. // tmp0\wtpwebapps下载
  51. aFilePath = request.getServletContext().getRealPath("uploadfiles");
  52. // 设置下载文件使用的报头
  53. response.setHeader("Content-Type", "application/x-msdownload");
  54. response.setHeader("Content-Disposition", "attachment; filename="
  55. + toUTF8String(filename));
  56. // 读入文件
  57. in = new FileInputStream(aFilePath + "\\" + filename);
  58. // 得到响应对象的输出流,用于向客户端输出二进制数据
  59. out = response.getOutputStream();
  60. out.flush();
  61. int aRead = 0;
  62. byte b[] = new byte[1024];
  63. while ((aRead = in.read(b)) != -1 & in != null) {
  64. out.write(b, 0, aRead);
  65. }
  66. out.flush();
  67. in.close();
  68. out.close();
  69. } catch (Throwable e) {
  70. e.printStackTrace();
  71. }
  72. logger.info("下载成功");
  73. return null;
  74. }
  75. /**
  76. * 下载保存时中文文件名的字符编码转换方法
  77. */
  78. public String toUTF8String(String str) {
  79. StringBuffer sb = new StringBuffer();
  80. int len = str.length();
  81. for (int i = 0; i < len; i++) {
  82. // 取出字符中的每个字符
  83. char c = str.charAt(i);
  84. // Unicode码值为0~255时,不做处理
  85. if (c >= 0 && c <= 255) {
  86. sb.append(c);
  87. } else { // 转换 UTF-8 编码
  88. byte b[];
  89. try {
  90. b = Character.toString(c).getBytes("UTF-8");
  91. } catch (UnsupportedEncodingException e) {
  92. e.printStackTrace();
  93. b = null;
  94. }
  95. // 转换为%HH的字符串形式
  96. for (int j = 0; j < b.length; j++) {
  97. int k = b[j];
  98. if (k < 0) {
  99. k &= 255;
  100. }
  101. sb.append("%" + Integer.toHexString(k).toUpperCase());
  102. }
  103. }
  104. }
  105. return sb.toString();
  106. }
  107. }

2)创建文件列表页面

下载文件示例需要一个显示被下载文件的 JSP 页面 showDownFiles.jsp,代码如下:

  1. <%@ page language="java" contentType="text/html; charset=UTF-8"
  2. pageEncoding="UTF-8"%>
  3. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
  4. <head>
  5. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  6. <title>Insert title here</title>
  7. </head>
  8. <body>
  9. <table>
  10. <tr>
  11. <td>被下载的文件名</td>
  12. </tr>
  13. <!--遍历 model中的 files-->
  14. <c:forEach items="${files}" var="filename">
  15. <tr>
  16. <td>
  17. <a href="${pageContext.request.contextPath }/down?filename=${filename}">${filename}</a>
  18. </td>
  19. </tr>
  20. </c:forEach>
  21. </table>
  22. </body>
  23. </html>

3)测试下载功能

发布 springMVCDemo11 应用到 Tomcat 服务器并启动 Tomcat 服务器,然后通过地址“http://localhost:8080/springMVCDemo11/showDownFiles”测试下载示例,运行结果如图 1 所示。
34-Spring MVC文件下载 - 图1
单击图 1 中的超链接下载文件,需要注意的是,使用浏览器演示该案例,不能在 MyEclipse 中演示下载案例。