⭐表示重要。

第一章:准备工作

  • 略(基于 SpringMVC v5.3.12 的环境)。

第二章:初始形态

  • 使用超链接指向要下载的文件,浏览器会尽可能的解析对应的文件,只要能在浏览器中显示的,就直接显示,而不是提示下载。
  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>首页</title>
  6. </head>
  7. <body>
  8. <a th:href="@{/download/hello.mp4}">下载 hello.mp4</a><br/>
  9. <a th:href="@{/download/hello.jpg}">下载 hello.jpg</a><br/>
  10. <a th:href="@{/download/hello.zip}">下载 hello.zip</a><br/>
  11. </body>
  12. </html>
  • 上面,只有 hello.zip 文件是直接提示下载的,其他两个都是直接显示。

第三章:明确要求浏览器提示下载(⭐)

  • 步骤:
  • ① 设置响应头:
    • Content-Disposition = attachment; filename=文件名
    • Content-Length = 文件的长度
  • ② 使用 IO流 将文件写出到响应流。

  • 示例:

  • 表单
  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>首页</title>
  6. </head>
  7. <body>
  8. <a th:href="@{/download}">下载</a>
  9. </body>
  10. </html>
  • 下载
  1. package com.github.fairy.era.mvc.handler;
  2. import org.apache.commons.io.IOUtils;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.stereotype.Controller;
  7. import org.springframework.web.bind.annotation.GetMapping;
  8. import javax.servlet.ServletContext;
  9. import javax.servlet.http.HttpServletResponse;
  10. import java.io.File;
  11. import java.io.IOException;
  12. import java.io.InputStream;
  13. /**
  14. * @author 许大仙
  15. * @version 1.0
  16. * @since 2021-11-11 14:58
  17. */
  18. @Controller
  19. public class DownloadHandler {
  20. private final Logger logger = LoggerFactory.getLogger(this.getClass());
  21. @Autowired
  22. private ServletContext servletContext;
  23. @GetMapping("/download")
  24. public void download(HttpServletResponse response) throws IOException {
  25. // 设置响应头
  26. response.setHeader("Content-Disposition", "attachment; filename=hello.jpg");
  27. File file = new File(servletContext.getRealPath("/download/hello.jpg"));
  28. response.setHeader("Content-Length", String.valueOf(file.length()));
  29. // 获取要下载的文件的输入流对象
  30. // 这里指定的路径以 Web 应用根目录为基准
  31. InputStream inputStream = servletContext.getResourceAsStream("/download/hello.jpg");
  32. IOUtils.copy(inputStream, response.getOutputStream());
  33. }
  34. }
  • 示例:
  • 表单
  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>首页</title>
  6. </head>
  7. <body>
  8. <a th:href="@{/download}">下载</a>
  9. </body>
  10. </html>
  • 下载
  1. package com.github.fairy.era.mvc.handler;
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.http.HttpHeaders;
  6. import org.springframework.http.HttpStatus;
  7. import org.springframework.http.ResponseEntity;
  8. import org.springframework.stereotype.Controller;
  9. import org.springframework.util.MultiValueMap;
  10. import org.springframework.web.bind.annotation.GetMapping;
  11. import javax.servlet.ServletContext;
  12. import javax.servlet.http.HttpServletResponse;
  13. import java.io.File;
  14. import java.io.IOException;
  15. import java.io.InputStream;
  16. /**
  17. * @author 许大仙
  18. * @version 1.0
  19. * @since 2021-11-11 14:58
  20. */
  21. @Controller
  22. public class DownloadHandler {
  23. private final Logger logger = LoggerFactory.getLogger(this.getClass());
  24. @Autowired
  25. private ServletContext servletContext;
  26. @GetMapping("/download")
  27. public ResponseEntity<byte[]> download(HttpServletResponse response) throws IOException {
  28. // 获取要下载的文件的输入流对象
  29. // 这里指定的路径以 Web 应用根目录为基准
  30. InputStream inputStream = servletContext.getResourceAsStream("/download/hello.jpg");
  31. try {
  32. // 2.将要下载的文件读取到字节数组中
  33. // ①获取目标文件的长度
  34. int len = inputStream.available();
  35. // ②根据目标文件长度创建字节数组
  36. byte[] buffer = new byte[len];
  37. // ③将目标文件读取到字节数组中
  38. inputStream.read(buffer);
  39. // 3.封装响应消息头
  40. // ①创建MultiValueMap接口类型的对象,实现类是HttpHeaders
  41. MultiValueMap responseHeaderMap = new HttpHeaders();
  42. // ②存入下载文件所需要的响应消息头
  43. responseHeaderMap.add("Content-Disposition", "attachment; filename=hello.jpg");
  44. File file = new File(servletContext.getRealPath("/download/hello.jpg"));
  45. responseHeaderMap.add("Content-Length", String.valueOf(file.length()));
  46. // ③创建ResponseEntity对象
  47. ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(buffer, responseHeaderMap, HttpStatus.OK);
  48. // 4.返回responseEntity对象
  49. return responseEntity;
  50. } catch (IOException e) {
  51. e.printStackTrace();
  52. } finally {
  53. if (inputStream != null) {
  54. try {
  55. inputStream.close();
  56. } catch (IOException e) {
  57. e.printStackTrace();
  58. }
  59. }
  60. }
  61. return null;
  62. }
  63. }

第四章:典型应用场景

  • 目前实现的是一个较为简单的下载,可以用在下面的一些场合:
  • ① 零星小文件下载。
  • ② 将系统内部的数据导出为 Excel、PDF 等格式,然后以下载的方式返回给用户。