springboot3+element-plus实现文件上传下载功能

37 阅读4分钟

从零开始实现文件的上传下载功能,如果不清楚怎么搭建springboot3工程,可以看这篇笔记十分钟快速启一个后端接口,看到新建controller就可以。然后跟着下面的步骤,一步一步来就可以实现。

1. 先安装一个hutool工具包,方便处理数据

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.25</version>
</dependency>

image.png

2.新建FileController

image.png

1.1 文件上传接口

关键代码如下:都添加了注释,每一个步骤都解释的很清楚。


@RestController
@RequestMapping("/files")
public class FileController {
    // 4. 使用系统属性获取当前工作目录(项目根路径),并拼接"/files/"作为文件存储目录
    // 系统属性"user.dir"返回JVM启动路径(通常是项目根目录)
    private static final String filePath = System.getProperty("user.dir") + "/files/";

    //    文件上传的接口
    @PostMapping("/upload")
    public Result upload(MultipartFile file) {// // 1. 接收前端以multipart/form-data格式提交的文件
        String originalFilename = file.getOriginalFilename();//. 2.获取原始文件名(含扩展名,如"test.png")
        // 3. 检查目标目录是否存在(FileUtil.isDirectory判断路径是否为目录)
        if (!FileUtil.isDirectory(filePath)) {
            FileUtil.mkdir(filePath);
        }
        // 5. 生成唯一文件名:时间戳 + 原始文件名(避免文件名冲突)
        String fileName = System.currentTimeMillis() + "_" + originalFilename;
        // 6. 拼接文件在服务器上的绝对路径
        String realPath = filePath + fileName;
        try {
            // 7. 将文件内容写入磁盘(FileUtil.writeBytes封装了文件写入操作)
            FileUtil.writeBytes(file.getBytes(), realPath);
            // 参数1: file.getBytes() 获取文件字节数组
            // 参数2: realPath 文件存储的完整物理路径
        } catch (IOException e) {
            throw new CustomException("500", "文件上传失败");
        }
        // 8. 构建文件访问URL(假设服务可通过/files/download路径提供文件下载)
        String url= "http://localhost:9090/files/download"+fileName;
        return Result.success(url);
    }

}

ps: 代码中的错误处理函数我放在文章最后面

关键代码解析:

  1. System.getProperty("user.dir")

    • 功能:获取JVM启动的工作目录(通常是项目根目录)
    • 示例输出:/home/projects/myapp
  2. FileUtil.isDirectory()  (来自hutool工具包)

    • 功能:检查指定路径是否为已存在的目录
    • 返回:true(是目录且存在) / false(不存在或不是目录)
  3. FileUtil.mkdir()  (来自hutool工具包)

    • 功能:递归创建目录(自动创建父目录)
    • 示例:mkdir("/a/b/c")会连续创建a、b、c三级目录
  4. MultipartFile.getOriginalFilename()

    • 功能:获取客户端上传文件的原始文件名(包含扩展名)
  5. FileUtil.writeBytes()  (来自hutool工具包)

    • 功能:将字节数组写入指定路径
    • 等效于Java原生:Files.write(Paths.get(realPath), bytes)
  6. MultipartFile.getBytes()

    • 功能:将上传文件内容转换为字节数组

对接口进行验证,使用apipost进行接口测试

image.png

1.2 文件下载接口

// 文件下载接口(GET请求)
    @GetMapping("/download/{fileName}")
    public void download(@PathVariable String fileName, HttpServletResponse response) {
        try {
            // 1. 设置响应内容类型为二进制流(通用文件下载格式)
            // 浏览器会将其识别为需要下载的文件,而不是直接打开
            response.setContentType("application/octet-stream");

            // 2. 设置Content-Disposition响应头,控制浏览器下载行为
            // "attachment"表示作为附件下载(而不是内联显示)
            // filename指定下载时保存的默认文件名(使用URL编码解决中文乱码问题)
            response.addHeader("Content-Disposition", "attachment; filename=" +
                    URLEncoder.encode(fileName, StandardCharsets.UTF_8));

            // 3. 获取响应输出流(用于向客户端发送文件数据)
            OutputStream os = response.getOutputStream();

            // 4. 拼接文件在服务器上的完整物理路径
            String realPath = filePath + fileName;

            // 5. 读取文件内容到字节数组(FileUtil.readBytes来自hutool工具包)
            byte[] bytes = FileUtil.readBytes(realPath);

            // 6. 将文件字节流写入响应输出流
            os.write(bytes);

            // 7. 刷新输出流确保数据完全发送
            os.flush();

            // 8. 关闭输出流释放资源
            os.close();
        } catch (IOException e) {
            // 9. 异常处理:文件操作出错时抛出业务异常
            throw new CustomException("500", "文件下载失败");
        }
    }

关键代码解析:

  1. @GetMapping("/download/{fileName}")

    • 定义GET请求端点,{fileName}为路径参数
    • 示例访问路径:http://localhost:9090/files/download/1686543211234_logo.png
  2. @PathVariable String fileName

    • 从URL路径中提取文件名参数
    • 如访问/download/test.jpg → fileName="test.jpg"
  3. HttpServletResponse

    • 用于直接操作HTTP响应(设置头信息/输出流)
    • 相比返回对象,提供更底层的响应控制
  4. response.setContentType("application/octet-stream")

    • MIME类型设置为二进制流
    • 强制浏览器触发下载行为而非直接打开文件
  5. Content-Disposition响应头

    • attachment:指示浏览器应保存文件
    • filename:指定下载时的默认文件名
    • URLEncoder.encode():解决中文文件名乱码问题

对接口进行验证,浏览器输入地址即可 image.png