定制软件SpringBoot实现文件上传和下载

1.用IDEA创建名叫springboot-file的SpringBoot项目,并将Package name 改为com.example.springboot,导入Spring Web和thymeleaf依赖。(定制软件如果创建过程中遇到了问题,定制软件可以看我写的文章《》定制软件中前三个步骤。)

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  8. </dependency>

2.定制软件文件上传分为单文件上定制软件传和多文件上传,定制软件这里通过一个方法实现。在src/main/resources/templates定制软件文件下创建upload.html文件。

  1. <!DOCTYPE html>
  2. <html xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. </head>
  5. <body>
  6. <form th:action="@{/upload}" method="post" enctype="multipart/form-data">
  7. 定制软件选择单个文件<input type="file" name="file"><br><br>
  8. 定制软件选择多个文件<input type="file" name="files" multiple><br><br>
  9. <input type="submit" value="上传">
  10. </form>
  11. </body>
  12. </html>

3.在src/main/resources文件下的application.properties文件中,定制软件添加文件保存的路径。

filePath=E:/springboot_save_file/

4.在src/main/resources的com.example.springboot文件夹下,创建包controller,并创建FileController类,定制软件用于处理所有的文件上定制软件传和下载请求。(定制软件由于下载页面还没写,定制软件所以上传文件完成后,会报404错误,定制软件但是不影响功能)

  1. package com.example.springboot.controller;
  2. import cn.hutool.extra.servlet.ServletUtil;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.springframework.beans.factory.annotation.Value;
  5. import org.springframework.stereotype.Controller;
  6. import org.springframework.ui.Model;
  7. import org.springframework.web.bind.annotation.*;
  8. import org.springframework.web.multipart.MultipartFile;
  9. import javax.servlet.http.HttpServletResponse;
  10. import java.io.File;
  11. import java.io.FileInputStream;
  12. import java.io.IOException;
  13. import java.io.OutputStream;
  14. import java.nio.CharBuffer;
  15. import java.nio.charset.Charset;
  16. import java.nio.charset.CharsetEncoder;
  17. import java.util.List;
  18. @Controller
  19. public class FileController {
  20. //读取application.properties文件中的filePath属性
  21. @Value("${filePath}")
  22. private String filePath;
  23. /**
  24. * 定制软件前往上传页面
  25. * @return 页面名称
  26. */
  27. @GetMapping({"/upload", ""})
  28. public String goIndex() {
  29. return "upload";
  30. }
  31. /**
  32. * 定制软件将文件保存到指定文件夹
  33. * @param file 单个文件
  34. * @param files 多个文件
  35. * @return 重定向到controller定制软件层中定制软件前往下载页面的url
  36. * @throws IOException
  37. */
  38. @PostMapping("/upload")
  39. public String uploadAndGoDownLoad(@RequestPart("file") MultipartFile file,
  40. @RequestPart("files") List<MultipartFile> files) throws IOException {
  41. //定制软件定制软件判断文件夹是否存在,不存在时,定制软件创建文件夹
  42. File directoryFile = new File(filePath);
  43. if (!directoryFile.exists()) {
  44. //定制软件创建多个文件夹
  45. directoryFile.mkdirs();
  46. }
  47. //定制软件判断文件是否为空,不为空时,保存文件
  48. if (!file.isEmpty()) {
  49. saveFile(file);
  50. }
  51. //定制软件判断上传文件个数是否为0
  52. if (files.size() > 0) {
  53. for (MultipartFile multipartFile : files) {
  54. if (!multipartFile.isEmpty()) {
  55. saveFile(multipartFile);
  56. }
  57. }
  58. }
  59. return "redirect:/goDownload";
  60. }
  61. /**
  62. * 定制软件保存所有的所有上传的文件名称,前往下载页面
  63. * @param model
  64. * @return 页面名称
  65. */
  66. @GetMapping("/goDownload")
  67. public String goDownload(Model model) {
  68. File file = new File(filePath);
  69. //判断文件夹是否存在
  70. if (file.exists()) {
  71. //获取文件夹下面的所有名称
  72. String[] list = file.list();
  73. model.addAttribute("fileNames", list);
  74. }
  75. return "download";
  76. }
  77. /**
  78. * 保存文件到指定位置
  79. * @param file 需要上传的文件
  80. * @throws IOException
  81. */
  82. public void saveFile(MultipartFile file) throws IOException {
  83. //获取文件名
  84. String name = file.getOriginalFilename();
  85. file.transferTo(new File(filePath + name));
  86. }
  87. }

注意:

1.前端向后端传递的form表单enctype属性的值必须"multipart/form-data。

2.前后端请求方式要一致,且必须为post。

3.@RequestPart注解最好加上,但是不加也可以。注意前后端参数的绑定,对于注解的使用,可以查看我写的《》。

结果:

5.对于文件上传功能,相对较为简单,这里就不具体说了。下面会具体介绍文件下载,前后端实现方式和注意的地方。文件下载和文件上传是连在一起的,都写在了FileController类中。首先前端写采用最简单的方式,实现文件下载,将后端实现方式讲完后,再讲其他前端实现方式。

  1. <!DOCTYPE html>
  2. <html xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <script>
  5. function downloadFileByOpen(fileName) {
  6. window.open("http://localhost:8080/download/hutool?fileName=" + fileName);
  7. }
  8. </script>
  9. </head>
  10. <body>
  11. <h3>后端hutool + 前端open方式</h3>
  12. <div th:if="${fileNames} == null">没有文件可下载</div>
  13. <ul>
  14. <li th:each="fileName : ${fileNames}" th:text="${fileName} + ' 下载'" th:onclick="downloadFileByOpen([[${fileName}]])">
  15. </li>
  16. </ul>
  17. </body>
  18. </html>

6.后端实现文件下载方式一:hutool方式。在pom.xml文件中导入hutool-extra的依赖,并设置CharacterEncoding为UTF-8。如果不设置CharacterEncoding,会出现中文文件名乱码。

  1. <dependency>
  2. <groupId>cn.hutool</groupId>
  3. <artifactId>hutool-extra</artifactId>
  4. <version>5.8.8</version>
  5. </dependency>
  1. package com.example.springboot.controller;
  2. import cn.hutool.extra.servlet.ServletUtil;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.springframework.beans.factory.annotation.Value;
  5. import org.springframework.stereotype.Controller;
  6. import org.springframework.ui.Model;
  7. import org.springframework.web.bind.annotation.*;
  8. import org.springframework.web.multipart.MultipartFile;
  9. import javax.servlet.http.HttpServletResponse;
  10. import java.io.File;
  11. import java.io.FileInputStream;
  12. import java.io.IOException;
  13. import java.io.OutputStream;
  14. import java.nio.CharBuffer;
  15. import java.nio.charset.Charset;
  16. import java.nio.charset.CharsetEncoder;
  17. import java.util.List;
  18. @Controller
  19. public class FileController {
  20. //读取application.properties文件中的filePath属性
  21. @Value("${filePath}")
  22. private String filePath;
  23. /**
  24. * 前往上传页面
  25. * @return 页面名称
  26. */
  27. @GetMapping({"/upload", ""})
  28. public String goIndex() {
  29. return "upload";
  30. }
  31. /**
  32. * 将文件保存到指定文件夹
  33. * @param file 单个文件
  34. * @param files 多个文件
  35. * @return 重定向到controller层中前往下载页面的url
  36. * @throws IOException
  37. */
  38. @PostMapping("/upload")
  39. public String uploadAndGoDownLoad(@RequestPart("file") MultipartFile file,
  40. @RequestPart("files") List<MultipartFile> files) throws IOException {
  41. //判断文件夹是否存在,不存在时,创建文件夹
  42. File directoryFile = new File(filePath);
  43. if (!directoryFile.exists()) {
  44. //创建多个文件夹
  45. directoryFile.mkdirs();
  46. }
  47. //判断文件是否为空,不为空时,保存文件
  48. if (!file.isEmpty()) {
  49. saveFile(file);
  50. }
  51. //判断上传文件个数是否为0
  52. if (files.size() > 0) {
  53. for (MultipartFile multipartFile : files) {
  54. if (!multipartFile.isEmpty()) {
  55. saveFile(multipartFile);
  56. }
  57. }
  58. }
  59. return "redirect:/goDownload";
  60. }
  61. /**
  62. * 保存所有的所有上传的文件名称,前往下载页面
  63. * @param model
  64. * @return 页面名称
  65. */
  66. @GetMapping("/goDownload")
  67. public String goDownload(Model model) {
  68. File file = new File(filePath);
  69. //判断文件夹是否存在
  70. if (file.exists()) {
  71. //获取文件夹下面的所有名称
  72. String[] list = file.list();
  73. model.addAttribute("fileNames", list);
  74. }
  75. return "download";
  76. }
  77. /**
  78. * 使用Hutool实现文件下载
  79. * @param fileName 要下载的文件名
  80. * @param response
  81. */
  82. @GetMapping("/download/hutool")
  83. @ResponseBody
  84. public void downloadByHutool(@RequestParam(value = "fileName") String fileName,
  85. HttpServletResponse response) {
  86. //防止中文乱码
  87. response.setCharacterEncoding("UTF-8");
  88. ServletUtil.write(response,new File(filePath + fileName));
  89. }
  90. /**
  91. * 保存文件到指定位置
  92. * @param file 需要上传的文件
  93. * @throws IOException
  94. */
  95. public void saveFile(MultipartFile file) throws IOException {
  96. //获取文件名
  97. String name = file.getOriginalFilename();
  98. file.transferTo(new File(filePath + name));
  99. }
  100. }

7.后端实现方式二:通过查看Hutool源码,自己模仿着源码写的一种方式。将前端download.html文件中,添加方式二的测试。后端添加方式二的实现代码

  1. <!DOCTYPE html>
  2. <html xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <script>
  5. function downloadFileByOpen(fileName) {
  6. window.open("http://localhost:8080/download/hutool?fileName=" + fileName);
  7. }
  8. function downloadFileByOpenAndSelf(fileName) {
  9. window.open("http://localhost:8080/download/hutool/self?fileName=" + fileName);
  10. }
  11. </script>
  12. </head>
  13. <body>
  14. <h3>后端hutool + 前端open方式</h3>
  15. <div th:if="${fileNames} == null">没有文件可下载</div>
  16. <ul>
  17. <li th:each="fileName : ${fileNames}" th:text="${fileName} + ' 下载'" th:onclick="downloadFileByOpen([[${fileName}]])">
  18. </li>
  19. </ul>
  20. <br>
  21. <br>
  22. <h3>后端模仿hutool + 前端open方式</h3>
  23. <div th:if="${fileNames} == null">没有文件可下载</div>
  24. <ul>
  25. <li th:each="fileName : ${fileNames}" th:text="${fileName} + ' 下载'" th:onclick="downloadFileByOpenAndSelf([[${fileName}]])">
  26. </li>
  27. </ul>
  28. </body>
  29. </html>
  1. package com.example.springboot.controller;
  2. import cn.hutool.extra.servlet.ServletUtil;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.springframework.beans.factory.annotation.Value;
  5. import org.springframework.stereotype.Controller;
  6. import org.springframework.ui.Model;
  7. import org.springframework.web.bind.annotation.*;
  8. import org.springframework.web.multipart.MultipartFile;
  9. import javax.servlet.http.HttpServletResponse;
  10. import java.io.File;
  11. import java.io.FileInputStream;
  12. import java.io.IOException;
  13. import java.io.OutputStream;
  14. import java.nio.CharBuffer;
  15. import java.nio.charset.Charset;
  16. import java.nio.charset.CharsetEncoder;
  17. import java.util.List;
  18. @Controller
  19. public class FileController {
  20. //读取application.properties文件中的filePath属性
  21. @Value("${filePath}")
  22. private String filePath;
  23. /**
  24. * 前往上传页面
  25. * @return 页面名称
  26. */
  27. @GetMapping({"/upload", ""})
  28. public String goIndex() {
  29. return "upload";
  30. }
  31. /**
  32. * 将文件保存到指定文件夹
  33. * @param file 单个文件
  34. * @param files 多个文件
  35. * @return 重定向到controller层中前往下载页面的url
  36. * @throws IOException
  37. */
  38. @PostMapping("/upload")
  39. public String uploadAndGoDownLoad(@RequestPart("file") MultipartFile file,
  40. @RequestPart("files") List<MultipartFile> files) throws IOException {
  41. //判断文件夹是否存在,不存在时,创建文件夹
  42. File directoryFile = new File(filePath);
  43. if (!directoryFile.exists()) {
  44. //创建多个文件夹
  45. directoryFile.mkdirs();
  46. }
  47. //判断文件是否为空,不为空时,保存文件
  48. if (!file.isEmpty()) {
  49. saveFile(file);
  50. }
  51. //判断上传文件个数是否为0
  52. if (files.size() > 0) {
  53. for (MultipartFile multipartFile : files) {
  54. if (!multipartFile.isEmpty()) {
  55. saveFile(multipartFile);
  56. }
  57. }
  58. }
  59. return "redirect:/goDownload";
  60. }
  61. /**
  62. * 保存所有的所有上传的文件名称,前往下载页面
  63. * @param model
  64. * @return 页面名称
  65. */
  66. @GetMapping("/goDownload")
  67. public String goDownload(Model model) {
  68. File file = new File(filePath);
  69. //判断文件夹是否存在
  70. if (file.exists()) {
  71. //获取文件夹下面的所有名称
  72. String[] list = file.list();
  73. model.addAttribute("fileNames", list);
  74. }
  75. return "download";
  76. }
  77. /**
  78. * 使用Hutool实现文件下载
  79. * @param fileName 要下载的文件名
  80. * @param response
  81. */
  82. @GetMapping("/download/hutool")
  83. @ResponseBody
  84. public void downloadByHutool(@RequestParam(value = "fileName") String fileName,
  85. HttpServletResponse response) {
  86. //防止中文乱码
  87. response.setCharacterEncoding("UTF-8");
  88. ServletUtil.write(response,new File(filePath + fileName));
  89. }
  90. /**
  91. * 模仿hutool实现文件下载
  92. * @param fileName 要下载的文件名
  93. * @param response
  94. * @throws IOException
  95. */
  96. @GetMapping("/download/hutool/self")
  97. @ResponseBody
  98. public void downloadBySelfAndHutool(@RequestParam(value = "fileName") String fileName,
  99. HttpServletResponse response) throws IOException {
  100. //设置字符编码
  101. response.setCharacterEncoding("UTF-8");
  102. //以下模仿hutool进行相应设置
  103. //设置内容类型
  104. response.setHeader("Content-Type", "application/octet-stream");
  105. //设置文件名,是解决中文乱码的关键
  106. response.setHeader("Content-Disposition", String.format("attachment;filename=\"%s\"", URLEncoder.encode(fileName,"UTF-8")));
  107. //将文件取出,并写到response
  108. FileInputStream fileInputStream = new FileInputStream(filePath + fileName);
  109. OutputStream outputStream = response.getOutputStream();
  110. byte[] bytes = new byte[1024];
  111. int length;
  112. while ((length = fileInputStream.read(bytes)) != -1) {
  113. outputStream.write(bytes, 0, length);
  114. }
  115. fileInputStream.close();
  116. outputStream.flush();
  117. outputStream.close();
  118. }
  119. /**
  120. * 保存文件到指定位置
  121. * @param file 需要上传的文件
  122. * @throws IOException
  123. */
  124. public void saveFile(MultipartFile file) throws IOException {
  125. //获取文件名
  126. String name = file.getOriginalFilename();
  127. file.transferTo(new File(filePath + name));
  128. }
  129. }

8.上面两种后端实现文件下载方式,对于前端来说,无论是通过open方式,还是通过方式都可以使用。下面这种是通过返回值方式,这种方式主要用于前后端分离项目中。下面以原生的Ajax,模拟前后端分离项目,介绍前后端的实现方式。

download.html中添加Ajax和返回值方式实现文件下载的测试。

  1. <!DOCTYPE html>
  2. <html xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <script>
  5. function downloadFileByOpen(fileName) {
  6. window.open("http://localhost:8080/download/hutool?fileName=" + fileName);
  7. }
  8. function downloadFileByOpenAndSelf(fileName) {
  9. window.open("http://localhost:8080/download/hutool/self?fileName=" + fileName);
  10. }
  11. function downloadFileByAjax(fileName) {
  12. let xhr = new XMLHttpRequest;
  13. xhr.open("get","/download/return?fileName=" + fileName,true);
  14. //发送请求
  15. xhr.send();
  16. xhr.responseType="blob";
  17. xhr.onload = function() {
  18. if(this.status === 200) {
  19. let blob = new Blob([this.response]);
  20. let elink = document.createElement('a');
  21. elink.download = fileName;
  22. elink.style.display = 'none';
  23. elink.href = URL.createObjectURL(blob);
  24. document.body.appendChild(elink);
  25. elink.click();
  26. // 释放URL 对象
  27. URL.revokeObjectURL(elink.href);
  28. document.body.removeChild(elink);
  29. }
  30. }
  31. }
  32. </script>
  33. </head>
  34. <body>
  35. <h3>后端hutool + 前端open方式</h3>
  36. <div th:if="${fileNames} == null">没有文件可下载</div>
  37. <ul>
  38. <li th:each="fileName : ${fileNames}" th:text="${fileName} + ' 下载'"
  39. th:onclick="downloadFileByOpen([[${fileName}]])">
  40. </li>
  41. </ul>
  42. <br>
  43. <br>
  44. <h3>后端模仿hutool + 前端open方式</h3>
  45. <div th:if="${fileNames} == null">没有文件可下载</div>
  46. <ul>
  47. <li th:each="fileName : ${fileNames}" th:text="${fileName} + ' 下载'"
  48. th:onclick="downloadFileByOpenAndSelf([[${fileName}]])">
  49. </li>
  50. </ul>
  51. <br>
  52. <br>
  53. <h3>后端返回值 + 前端Ajax方式</h3>
  54. <div th:if="${fileNames} == null">没有文件可下载</div>
  55. <ul>
  56. <li th:each="fileName : ${fileNames}" th:text="${fileName} + ' 下载'"
  57. th:onclick="downloadFileByAjax([[${fileName}]])">
  58. </li>
  59. </ul>
  60. </body>
  61. </html>

FileController类中添加返回值方式实现文件上传的代码。(FileController类最终代码)

  1. package com.example.springboot.controller;
  2. import cn.hutool.extra.servlet.ServletUtil;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.springframework.beans.factory.annotation.Value;
  5. import org.springframework.stereotype.Controller;
  6. import org.springframework.ui.Model;
  7. import org.springframework.web.bind.annotation.*;
  8. import org.springframework.web.multipart.MultipartFile;
  9. import javax.servlet.http.HttpServletResponse;
  10. import java.io.File;
  11. import java.io.FileInputStream;
  12. import java.io.IOException;
  13. import java.io.OutputStream;
  14. import java.nio.CharBuffer;
  15. import java.nio.charset.Charset;
  16. import java.nio.charset.CharsetEncoder;
  17. import java.util.List;
  18. @Controller
  19. public class FileController {
  20. //读取application.properties文件中的filePath属性
  21. @Value("${filePath}")
  22. private String filePath;
  23. /**
  24. * 前往上传页面
  25. * @return 页面名称
  26. */
  27. @GetMapping({"/upload", ""})
  28. public String goIndex() {
  29. return "upload";
  30. }
  31. /**
  32. * 将文件保存到指定文件夹
  33. * @param file 单个文件
  34. * @param files 多个文件
  35. * @return 重定向到controller层中前往下载页面的url
  36. * @throws IOException
  37. */
  38. @PostMapping("/upload")
  39. public String uploadAndGoDownLoad(@RequestPart("file") MultipartFile file,
  40. @RequestPart("files") List<MultipartFile> files) throws IOException {
  41. //判断文件夹是否存在,不存在时,创建文件夹
  42. File directoryFile = new File(filePath);
  43. if (!directoryFile.exists()) {
  44. //创建多个文件夹
  45. directoryFile.mkdirs();
  46. }
  47. //判断文件是否为空,不为空时,保存文件
  48. if (!file.isEmpty()) {
  49. saveFile(file);
  50. }
  51. //判断上传文件个数是否为0
  52. if (files.size() > 0) {
  53. for (MultipartFile multipartFile : files) {
  54. if (!multipartFile.isEmpty()) {
  55. saveFile(multipartFile);
  56. }
  57. }
  58. }
  59. return "redirect:/goDownload";
  60. }
  61. /**
  62. * 保存所有的所有上传的文件名称,前往下载页面
  63. * @param model
  64. * @return 页面名称
  65. */
  66. @GetMapping("/goDownload")
  67. public String goDownload(Model model) {
  68. File file = new File(filePath);
  69. //判断文件夹是否存在
  70. if (file.exists()) {
  71. //获取文件夹下面的所有名称
  72. String[] list = file.list();
  73. model.addAttribute("fileNames", list);
  74. }
  75. return "download";
  76. }
  77. /**
  78. * 使用Hutool实现文件下载
  79. * @param fileName 要下载的文件名
  80. * @param response
  81. */
  82. @GetMapping("/download/hutool")
  83. @ResponseBody
  84. public void downloadByHutool(@RequestParam(value = "fileName") String fileName,
  85. HttpServletResponse response) {
  86. //防止中文乱码
  87. response.setCharacterEncoding("UTF-8");
  88. ServletUtil.write(response,new File(filePath + fileName));
  89. }
  90. /**
  91. * 模仿hutool实现文件下载
  92. * @param fileName 要下载的文件名
  93. * @param response
  94. * @throws IOException
  95. */
  96. @GetMapping("/download/hutool/self")
  97. @ResponseBody
  98. public void downloadBySelfAndHutool(@RequestParam(value = "fileName") String fileName,
  99. HttpServletResponse response) throws IOException {
  100. //设置字符编码
  101. response.setCharacterEncoding("UTF-8");
  102. //以下模仿hutool进行相应设置
  103. //设置内容类型
  104. response.setHeader("Content-Type", "application/octet-stream");
  105. //设置文件名,是解决中文乱码的关键
  106. response.setHeader("Content-Disposition", String.format("attachment;filename=\"%s\"", URLEncoder.encode(fileName,"UTF-8")));
  107. //将文件取出,并写到response
  108. FileInputStream fileInputStream = new FileInputStream(filePath + fileName);
  109. OutputStream outputStream = response.getOutputStream();
  110. byte[] bytes = new byte[1024];
  111. int length;
  112. while ((length = fileInputStream.read(bytes)) != -1) {
  113. outputStream.write(bytes, 0, length);
  114. }
  115. fileInputStream.close();
  116. outputStream.flush();
  117. outputStream.close();
  118. }
  119. /**
  120. * 通过返回值方式,实现文件下载
  121. * @param fileName 文件名
  122. * @return 文件流和请求头信息
  123. * @throws IOException
  124. */
  125. @GetMapping("/download/return")
  126. @ResponseBody
  127. public ResponseEntity<InputStreamResource> download(@RequestParam(value = "fileName") String fileName) throws IOException {
  128. // 读取文件
  129. String path = filePath + fileName;
  130. FileSystemResource file = new FileSystemResource(path);
  131. // 设置响应头
  132. HttpHeaders headers = new HttpHeaders();
  133. headers.add("Content-Disposition", String.format("attachment; filename=\"%s\"", file.getFilename()));
  134. return ResponseEntity
  135. .ok()
  136. .headers(headers)
  137. .contentLength(file.contentLength())
  138. .contentType(MediaType.parseMediaType("application/octet-stream"))
  139. .body(new InputStreamResource(file.getInputStream()));
  140. }
  141. /**
  142. * 保存文件到指定位置
  143. * @param file 需要上传的文件
  144. * @throws IOException
  145. */
  146. public void saveFile(MultipartFile file) throws IOException {
  147. //获取文件名
  148. String name = file.getOriginalFilename();
  149. file.transferTo(new File(filePath + name));
  150. }
  151. }

注意:

1.前端采用原生的ajax实现的,responseType最好设置为blob(设置为arraybuffer也可以,就是增加转换为blob的步骤)。(开始打算用jQuery中的ajax,但是设置responseType为blob会报错。查找原因,也解决不了。一般这种后端实现方式,对应的是前后端分离项目,然后前端使用的axios。我的能力也有限,知道解决方式的可以评论区留言,一起进步。

报错:jquery.js:10287 Uncaught DOMException: Failed to read the 'responseText' property from 'XMLHttpRequest': The value is only accessible if the object's 'responseType' is '' or 'text' (was 'blob').)

2.查看后端代码可以发现,这种下载文件的方式,我们不用去考虑中文乱码问题了。

9.前端使用,后端继续使用返回值方式,实现文件下载功能。以下是download.html最终代码。后端代码没有改变。这种前后端配合方式实现文件下载,在前后端分离项目中应用广泛(尤其在vue+springboot前后端组合中)。

  1. <!DOCTYPE html>
  2. <html xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <!-- 导入axios -->
  5. <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  6. <script>
  7. function downloadFileByOpen(fileName) {
  8. window.open("http://localhost:8080/download/hutool?fileName=" + fileName);
  9. }
  10. function downloadFileByOpenAndSelf(fileName) {
  11. window.open("http://localhost:8080/download/hutool/self?fileName=" + fileName);
  12. }
  13. function downloadFileByAjax(fileName) {
  14. let xhr = new XMLHttpRequest;
  15. xhr.open("get", "/download/return?fileName=" + fileName, true);
  16. //发送请求
  17. xhr.send();
  18. xhr.responseType = "blob";
  19. xhr.onload = function () {
  20. if (this.status === 200) {
  21. let blob = new Blob([this.response]);
  22. let elink = document.createElement('a');
  23. elink.download = fileName;
  24. elink.style.display = 'none';
  25. elink.href = URL.createObjectURL(blob);
  26. document.body.appendChild(elink);
  27. elink.click();
  28. // 释放URL 对象
  29. URL.revokeObjectURL(elink.href);
  30. document.body.removeChild(elink);
  31. }
  32. }
  33. }
  34. function downloadFileByAxios(fileName) {
  35. axios({
  36. url: "/download/return",
  37. method: "get",
  38. responseType: "blob",
  39. params: {
  40. fileName
  41. }
  42. }).then(function (res) {
  43. console.log(res);
  44. let blob = new Blob([res.data]);
  45. let elink = document.createElement('a');
  46. elink.download = fileName;
  47. elink.style.display = 'none';
  48. elink.href = URL.createObjectURL(blob);
  49. document.body.appendChild(elink);
  50. elink.click();
  51. // 释放URL 对象
  52. URL.revokeObjectURL(elink.href);
  53. document.body.removeChild(elink);
  54. })
  55. }
  56. </script>
  57. </head>
  58. <body>
  59. <h3>后端hutool + 前端open方式</h3>
  60. <div th:if="${fileNames} == null">没有文件可下载</div>
  61. <ul>
  62. <li th:each="fileName : ${fileNames}" th:text="${fileName} + ' 下载'"
  63. th:onclick="downloadFileByOpen([[${fileName}]])">
  64. </li>
  65. </ul>
  66. <br>
  67. <br>
  68. <h3>后端模仿hutool + 前端open方式</h3>
  69. <div th:if="${fileNames} == null">没有文件可下载</div>
  70. <ul>
  71. <li th:each="fileName : ${fileNames}" th:text="${fileName} + ' 下载'"
  72. th:onclick="downloadFileByOpenAndSelf([[${fileName}]])">
  73. </li>
  74. </ul>
  75. <br>
  76. <br>
  77. <h3>后端返回值 + 前端Ajax方式</h3>
  78. <div th:if="${fileNames} == null">没有文件可下载</div>
  79. <ul>
  80. <li th:each="fileName : ${fileNames}" th:text="${fileName} + ' 下载'"
  81. th:onclick="downloadFileByAjax([[${fileName}]])">
  82. </li>
  83. </ul>
  84. <br>
  85. <br>
  86. <h3>后端返回值 + 前端axios方式</h3>
  87. <div th:if="${fileNames} == null">没有文件可下载</div>
  88. <ul>
  89. <li th:each="fileName : ${fileNames}" th:text="${fileName} + ' 下载'"
  90. th:onclick="downloadFileByAxios([[${fileName}]])">
  91. </li>
  92. </ul>
  93. </body>
  94. </html>

SpringBoot实现文件上传和下载部分,到此结束了。我也是个新手,上面很多内容不够完善,甚至有些是错误的,请大家见谅。这是我在学习过程中做的笔记,感觉对大家可能有所帮助才发出来的,大家可以选择性查看。我也是在不断学习,不断完善自己。如果我在学习过程中,感觉对大家有用的部分,也会再次分享给大家的。谢谢!

上面有个问题还没有解决,也就是,前端怎么通过JQuery中的Ajax实现文件下载。这种方式和原生Ajax区别不大,下面就是代码,只需要设置返回类型为blob即可。(有时候,一个小问题,如果不熟悉,真的很难解决的。。。)

  1. $.ajax({
  2. type: "get",
  3. url: "/download/return",
  4. data: {
  5. fileName
  6. },
  7. xhrFields: { responseType: "blob" },
  8. success: function (response) {
  9. let blob = new Blob([response]);
  10. let elink = document.createElement('a');
  11. elink.download = fileName;
  12. elink.style.display = 'none';
  13. elink.href = URL.createObjectURL(blob);
  14. document.body.appendChild(elink);
  15. elink.click();
  16. // 释放URL 对象
  17. URL.revokeObjectURL(elink.href);
  18. document.body.removeChild(elink);
  19. }
  20. });

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发