Spring MVC学习随笔-文件下载和上传(配置文件上传解析器multipartResolver)

发布时间 2023-12-03 23:56:30作者: 扬眉剑出鞘

学习视频:孙哥说SpringMVC:结合Thymeleaf,重塑你的MVC世界!|前所未有的Web开发探索之旅
学习视频:【编程不良人】继spring之后快速入门springmvc,面对SpringMVC不用慌

六、SpringMVC 文件上传下载

6.1 文件上传

  1. 定义

    指的是用户将自己本地计算机中文件通过网络上传到系统所在服务器上的过程称为文件上传。

  2. 需要用户提交文件时,必须开发文件上传功能

  3. SpringMVC中如何开发文件上传

    1. 在系统中开发一个文件上传页面,包含一个form表单,表单中开发一个本地计算机文件入口

    2. form表单 method提交方式必须是post,添加属性:enctype = application/x-www-form-urlencoded(文本) | multipart/form-data

    3. 在SpringMVC配置文件加入文件上传解析器配置

      注意:文件上传解析器必须存在id,且id必须为multipartResolver

    4. 引入文件上传的相关依赖

      commons-fileupload

  • 编码

    distpacher.xml 进行文件上传解析器的配置
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
    
    // 引入相关依赖
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.4</version>
    </dependency>
    
    **// 传递的数据name属性名必须和控制器接受的形参名一致**
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>upload</title>
    </head>
    <body>
        <h1>文件上传</h1>
        <form action="${pageContext.request.contextPath}/file/upload" method="post" enctype="multipart/form-data">
            <input type="file" name="**img**"/>
            <input type="submit" value="上传文件"/>
        </form>
    </body>
    </html>
    

    在服务器上放置文件夹接受上传文件的步骤:在webapp下面创建一个文件夹(不能是空文件夹) ⇒ maven执行clean ⇒ 重启服务器,target下会自动创建此文件夹

```java
**控制层 通过MultipartFile形参接受页面传过来的文件,形参名必须与数据名(name属性)一致**
@Controller
@RequestMapping("file")
public class FileController {

    @RequestMapping("upload")
    public String upload(MultipartFile **img**, HttpServletRequest request) throws IOException {
        System.out.println("文件名" + img.getOriginalFilename());
        System.out.println("文件大小" + img.getSize());
        System.out.println("文件类型" + img.getContentType());
        // 文件上传
        // 1. 根据upload相对路径部署到服务之后的绝对路径 target/..../upload
        String realPath = request.getSession().getServletContext().getRealPath("/upload");
        // 2.将文件上传到upload对应路径
        img.transferTo(new File(realPath,img.getOriginalFilename()));
        return "index";
    }
}
```
  • 文件上传细节处理
    1. 如何修改文件上传的原始名称

      使用文件的原始名称做为上传文件的最终名称,会导致文件覆盖。所以每次用户上传文件需要修改一个新的名称。

      		// 重命名:获取后缀,随机命名  substring | 工具类 commons
              String fileName = img.getOriginalFilename();
      //        int i = fileName.lastIndexOf(".");
      //        String name = fileName.substring(i);
              String extension = FilenameUtils.getExtension(fileName);
              String newFileName = UUID.randomUUID().toString().replace("-","")+"."+extension;
              // 2.将文件上传到upload对应路径
              img.transferTo(new File(realPath,newFileName));
      
    2. 对上传的文件进行管理,将用户每天上传的文件放入当天日期目录中?

      // 3. 生成当天日期目录
      LocalDate now = LocalDate.now();
      File dateDir = new File(realPath, now.toString());
      if (!dateDir.exists()) {
          dateDir.mkdirs();
      }
      // 4.将文件上传到upload对应路径
      **img.transferTo(new File(dateDir,newFileName));
      
    3. SpringMVC中如何解决文件上传的大小限制

      注意:在SpringMVC中默认上传没有大小限制,所以需要限制用户上传文件的大小限制

6.2 文件下载

  1. 定义

    用户将服务器文件下载到本地计算机的过程称为文件下载

  2. 开发文件下载

    1. 确定系统中哪些文件需要用户下载
    2. 将需要下载的文件放入指定下载目录中
    3. 开发一个页面提供文件下载链接
    4. 开发下载Controller
  • 编码

    <body>
        <h1>文件下载</h1>
        <a href="${pageContext.request.contextPath}/file/download?fileName=aa.txt">aa.txt</a>
    </body>
    
    /* 处理文件下载*/
    @RequestMapping("download")
    public void download(String fileName, HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println("下载文件的名称 = " + fileName);
        // 1. 根据下载相对目录获取下载目录在服务器部署之后的绝对目录
        String realPath = request.getSession().getServletContext().getRealPath("/down");
        // 2.通过文件输入流读取文件
        FileInputStream is = new FileInputStream(new File(realPath, fileName));
        // 3.获取响应输出流
        response.setContentType("text/plain;charset=UTF-8");
        ServletOutputStream os = response.getOutputStream();
        // 4.附件下载文件  attachment(附件)  inline(在线打开)
        response.setHeader("content-disposition", "attachment;fileName=" + fileName);
        // 5.处理下载流复制
        // aa.txt
        int len;
        byte[] b = new byte[1024];
        while (true) {
            len = is.read(b);
            if (len == -1) {
                break;
            }
            os.write(b, 0, len);
        }
        is.close();
        os.close();
    }
    

6.3 文件下载细节处理

  • 实现在线打开下载+附件下载的功能(如下图)

  • 编码

    **// 通过url传递的数据控制参数变为inline或attachment**
    /* 处理文件下载*/
        @RequestMapping("download")
        public void download(String **openStyle**, String fileName, HttpServletRequest request, HttpServletResponse response) throws IOException {
    				**openStyle=openStyle==null?"inline":"attachment";**
            System.out.println("下载文件的名称 = " + fileName);
            // 1. 根据下载相对目录获取下载目录在服务器部署之后的绝对目录
            String realPath = request.getSession().getServletContext().getRealPath("/down");
            // 2.通过文件输入流读取文件
            FileInputStream is = new FileInputStream(new File(realPath, fileName));
            // 3.获取响应输出流
            response.setContentType("text/plain;charset=UTF-8");
            ServletOutputStream os = response.getOutputStream();
            // 4.附件下载文件  attachment(附件)  inline(在线打开)
            response.setHeader("content-disposition", **openStyle**+";fileName=" + fileName);
            // 5.处理下载流复制
            // 传统写法 aa.txt
    //        int len;
    //        byte[] b = new byte[1024];
    //        while (true) {
    //            len = is.read(b);
    //            if (len == -1) {
    //                break;
    //            }
    //            os.write(b, 0, len);
    //        }
    //        is.close();
    //        os.close();
            // 代替上面传统写法,commons包提供了io流更方便  操作io流使用IOUtils  操作file 用 FileUtils
            **IOUtils.copy(is, os);// 输入流拷贝到输出流
            IOUtils.closeQuietly(is);// 优雅关闭 安静关流
            IOUtils.closeQuietly(os);// 优雅关闭 安静关流**
    
        }
    
    <h1>文件下载</h1>
    <ul>
        <li>
            aa.txt
            <a href="${pageContext.request.contextPath}/file/download?fileName=aa.txt">在线打开</a>
            <a href="${pageContext.request.contextPath}/file/download?fileName=aa.txt&openStyle=attachment">附件下载</a>
        </li>
        <li>
            springmvc.png
            <a href="${pageContext.request.contextPath}/file/download?fileName=springmvc.png">在线打开</a>
            <a href="${pageContext.request.contextPath}/file/download?fileName=springmvc.png&openStyle=attachment">附件下载</a>
        </li>
        <li>
            自我介绍.txt
            <a href="${pageContext.request.contextPath}/file/download?fileName=自我介绍.txt">在线打开</a>
            <a href="${pageContext.request.contextPath}/file/download?fileName=自我介绍.txt&openStyle=attachment">附件下载</a>
        </li>
    </ul>
    
  • 解决文件名为中文时,下载后文件名变为乱码的问题

    // 对fileName编码,转为UTF-8
    response.setHeader("content-disposition", openStyle+";fileName=" + **URLEncoder.encode(fileName,"UTF-8")**);