SpringBoot的文件上传与下载

SpringBoot的文件上传与下载

技术概述

  文件的上传与下载是Web应用常用的功能。例如本博客园就拥有文件上传和附件下载的功能。博客内容也可直接上传图片并显示。SpringBoot是Web应用开发的主流框架,支持文件上传与下载操作。其中文件上传可分为单文件上传和多文件上传。

SpringBoot的文件上传下载实现大致步骤如下

  1. 前端编写上传控件
  2. 在Controller分别实现单文件上传、多文件上传与文件下载方法
  3. (可选)进行文件上传相关配置

具体实现步骤

1)前端上传控件编写

  注意声明form的enctype属性为multipart/form-data

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上传</title>
</head>
<body>
    <h3>单文件上传</h3>
    <form method="post" action="upload" enctype="multipart/form-data">
        <input type="file" name="file"/>
        <br/><br/>
        <input type="submit" value="上传">
    </form>
    <br/><hr/>
    <h3>多文件上传</h3>
    <form method="post" action="multiUpload" enctype="multipart/form-data">
        <input type="file" name="file" value="选择文件1"/>
        <br/><br/>
        <input type="file" name="file" value="选择文件2"/>
        <br/><br/>
        <input type="submit" value="上传">
    </form>
</body>
</html>

2)声明文件上传与下载路径常量

  一般而言,文件保存路径和下载路径是固定的,因此最好将其声明为常量,当路径要修改时也只需修改常量即可。

private static final String UPLOAD_PATH = "C:/Temp/";
private static final String DOWNLOAD_PATH = "C:/Java/";

3)实现文件上传方法

文件上传方法的思路主要如下

  1. 空文件不执行上传操作。
  2. 给文件按照一定的命名规则进行重命名。此举即可以防止命名冲突,也可以从一定程度上防止病毒木马等入侵,此处采用UUID实现重命名,当然也可以采取其它命名策略(如SHA、MD5等),但是要保证命名的合理性和安全性。
  3. 若文件命名策略可能生成同名文件(如两个用户上传了同一个文件),可采用后上传的文件不执行保存操作。
@PostMapping("upload")
@ResponseBody
public String upload(@RequestParam("file") MultipartFile file) {
    //不可以上传空文件
    if(file.isEmpty()) {
        return "文件为空,请选择文件后再上传";
    }

    String filename = file.getOriginalFilename();
    String suffix = filename.substring(filename.lastIndexOf("."));
    filename = UPLOAD_PATH + UUID.randomUUID() + suffix;
    File dest = new File(filename);

    //若文件已存在则不执行保存操作
    try {
        if(!dest.exists()) {
            file.transferTo(dest);
        }
    } catch (Exception e) {
        e.printStackTrace();
        return "上传失败";
    }

    return "上传成功";
}

4)实现多文件上传方法

  相比单文件上传,多文件上传要先从request中获取文件列表,然后再对列表中的文件一一处理即可,处理策略同上述单文件上传方法

@PostMapping("multiUpload")
@ResponseBody String multiUpload(HttpServletRequest request) {

    List<MultipartFile> list = ((MultipartHttpServletRequest)request).getFiles("file");

    for(MultipartFile file : list) {
        //不可以上传空文件
        if(file.isEmpty()) {
            return "某文件为空,请选择文件后再上传";
        }

        String filename = file.getOriginalFilename();
        String suffix = filename.substring(filename.lastIndexOf("."));
        filename = UPLOAD_PATH + UUID.randomUUID() + suffix;
        File dest = new File(filename);

        //若文件已存在则不执行保存操作
        try {
            if(!dest.exists()) {
                file.transferTo(dest);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return "上传失败";
        }
    }

    return "上传成功";
}

5)实现文件下载方法

  要记得判断所需求的文件是否存在,并设置header

@GetMapping("download")
@ResponseBody
public String download(HttpServletResponse response, String requestFilename) {

    File file = new File(DOWNLOAD_PATH + requestFilename);
    if (!file.exists()) {
        return "所访问的资源不存在";
    }

    try {
        FileInputStream fis = new FileInputStream(file);
        // 设置相关格式
        response.setContentType("application/force-download");
        // 设置下载后的文件名以及header
        response.addHeader("Content-disposition", "attachment;fileName=" + file.getName());
        OutputStream os = response.getOutputStream();
        byte[] buffer = new byte[DOWNLOAD_BUFFER_SIZE];
        int len = 0;
        while((len = fis.read(buffer)) != -1) {
            os.write(buffer, 0, len);
        }
        fis.close();
    } catch (Exception e) {
        e.printStackTrace();
        return "下载失败";
    }

    return "开始下载";
}

6)(可选)文件上传相关配置

  在application.properties或application.yml中可设置单个文件最大值max-file-size以及允许上传文件总大小max-requset-size,下以yml为例

spring:
  servlet:
    multipart:
      max-file-size: 8MB
      max-requset-size: 16MB

结果展示

  上传三张图片,分别使用单文件和多文件上传

问题总结

  1. 要切记前端控件的name的值要和controller方法中参数的名称要一致。
  2. 要根据不同情况选择不同的命名策略,若无特殊要求,推荐UUID + 日期 + 后缀名的命名方式.
  3. 有时要上传静态资源文件,而且前端需要立刻使用上传后的文件,那么就需要实现SpringBoot热部署,该内容不在本篇博客的讨论范围,具体请移步SpringBoot实现热部署

参考资料和链接

SpringBoot5.2.7参考文档
CSDN博客:SpringBoot的文件上传与下载

原文地址:https://www.cnblogs.com/zwn-blog/p/13138171.html