Java Spring Boot 中集成文件上传和下载功能

发布时间 2024-01-03 11:37:01作者: 进击的davis

在日常开发中,可能会遇到文件上传下载的需求,今天简单学习下,在项目开发中,如果遇到类似需求,该如何应对。

在 Spring Boot 项目中如果增加 文件上传下载 的功能,其实也挺简单,无非就是增加接口而已,但具体实现需要根据需求来定,通常我们的上传,可能会限制文件类型,限制文件大小,或者是限制文件数量,然后在将文件上传到指定服务器后,我们通常在数据库中也会存储一个用户文件的对应目录位置,便于后期请求处理。

当然一些可以通用处理的功能,我们应该将其在 拦截件 中实现,比如文件类型,文件大小,包括请求大小,万一用户上传个超大的文件,这对我们后台肯定不允许的,除非说你的后台就是一个网盘,不然通常的业务场景都要限制下这些因素。

话不多说,我们看看单个文件、多个文件上传,文件下载可以怎么实现吧。

单个文件上传

在编写接口时,我们需要限定在表单中的字段名,因为我们需要通过 Spring Boot 的注解来获取对应资源,在上传接口中,最好也对上传的文件做一些限制。

package com.example.springbootmybatisplusdemo.controller;

import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.*;

@RestController
@RequestMapping("/file")
public class FileHandleController {

    private static String UPLOAD_DIR = System.getProperty("user.dir") + File.separator + "uploads";

    @PostMapping("/upload/single")
    public String upload(@RequestParam("file") MultipartFile file) throws IOException {
        System.out.println(String.format("File: %s is about to uploading...", file.getName()));

        // handle upload file type, may handle in interceptor
        String contentTyp = file.getContentType();;
        switch (contentTyp) {
            case "text/csv":
                System.out.println("content-type:" + "text/csv");
                break;
            case "application/pdf":
                System.out.println("content-type:" + "application/pdf");
                break;
            case "image/png":
                System.out.println("content-type:" + "image/png");
                break;
            case "image/jpg":
                System.out.println("content-type:" + "image/jpg");
                break;
            default:
                System.out.println("content-type:" + contentTyp);
        }
        // handle file size, handle in interceptor
        long size = file.getSize();
        if (size > 5 * 1024 * 1024) {
            return "size out of limit.";
        }

        if (file.getSize() == 0) {
            return "empty file!";
        }

        String newFileName = save(file);
        return newFileName;
    }

    private String save(MultipartFile file) throws IOException {
        String newFileName = file.getOriginalFilename() + "-" +  System.currentTimeMillis();
        final Path filePath = Paths.get(UPLOAD_DIR, newFileName);
        // method-1
        Files.write(filePath, file.getBytes());
        // method-2
        // file.transferTo(new File(filePath.toString()));

        System.out.println("file saved to: " + filePath);
        return newFileName;
    }
}

多个文件上传

多文件上传,其实和单个文件上传类似,我们不过是处理一个资源列表文件,其他和单个文件类似。

package com.example.springbootmybatisplusdemo.controller;

import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.*;

@RestController
@RequestMapping("/file")
public class FileHandleController {

    private static String UPLOAD_DIR = System.getProperty("user.dir") + File.separator + "uploads";

    @PostMapping("/upload/multi")
    public String upload(@RequestParam("files") MultipartFile[] files) throws IOException {
        System.out.println(files.getClass().getName());
        StringBuilder sb = new StringBuilder();

        for (MultipartFile file: files) {
            if (file.getSize() <= 0) {
                continue;
            }

            System.out.println("file type: " + file.getContentType());

            final String newFileName = save(file);
            System.out.println("upload file: " + file.getName());

            sb.append(newFileName);
            sb.append(", ");
        }

        return sb.toString();
    }

    private String save(MultipartFile file) throws IOException {
        String newFileName = file.getOriginalFilename() + "-" +  System.currentTimeMillis();
        final Path filePath = Paths.get(UPLOAD_DIR, newFileName);
        // method-1
        Files.write(filePath, file.getBytes());
        // method-2
        // file.transferTo(new File(filePath.toString()));

        System.out.println("file saved to: " + filePath);
        return newFileName;
    }

}

文件下载

文件下载,根据提交的文件信息,在我们的资源服务器中查找是否有,然后读取,写入到 response 中,注意,我们需要在 header 中声明相关的配置信息。

package com.example.springbootmybatisplusdemo.controller;

import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.*;

@RestController
@RequestMapping("/file")
public class FileHandleController {

    private static String UPLOAD_DIR = System.getProperty("user.dir") + File.separator + "uploads";

    @GetMapping("/download")
    public boolean download(@RequestParam("fileName") String fileName, HttpServletResponse response) {
        String filePath = UPLOAD_DIR + File.separator + fileName;
        System.out.println(filePath);
        Path path = Paths.get(filePath);

        boolean flag = false;

        // method-1
        if (Files.exists(path) && Files.isReadable(path)) {
            // read and copy
            File file = new File(filePath);
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);

            byte[] buf = new byte[1024];
            BufferedInputStream bis = null;
            OutputStream out = null;

            try {
                out = response.getOutputStream();
                bis = new BufferedInputStream(new FileInputStream(file));
                int i = bis.read(buf);
                while (i != -1) {
                    out.write(buf, 0, buf.length);
                    out.flush();
                    i = bis.read(buf);
                }

                flag = true;
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                System.out.println("FileNotFoundException");
            } catch (IOException e) {
                e.printStackTrace();
                System.out.println("IOException");
            } finally {
                if (bis != null) {
                    try {
                        bis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                        System.out.println("bis Close exception");
                    }
                }
            }
        }

        // method-2
        /**
        try {
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.setContentType("application/octet-stream");
            Files.copy(path, response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("download file error");
        }
        */


        System.out.println("file download result: " + flag);
        return flag;
    }
}

参考: