Spring Boot 文件上传详解:深入理解 MultipartFile 的使用与原理

在 Java Web 开发中,文件上传是一项非常常见的需求,例如上传头像、Excel 文件、图片、PDF、视频等。Spring MVC 为我们提供了 MultipartFile 接口,使文件上传变得十分简单。本文将从原理、常用 API、实际开发、注意事项以及面试角度,全面介绍 MultipartFile


一、什么是 MultipartFile?

MultipartFile 是 Spring MVC 提供的一个接口,用于接收客户端上传的文件。

当前端通过 <input type="file"> 上传文件时,浏览器会采用 multipart/form-data 编码格式发送 HTTP 请求,SpringMVC 会自动解析请求,并封装成 MultipartFile 对象。

也就是说:

MultipartFile 本质上就是 SpringMVC 对上传文件的一层封装。

开发者无需自己解析 HTTP 请求体,只需要接收 MultipartFile 即可。

例如:

复制代码
@PostMapping("/upload")
public String upload(MultipartFile file){
    return "success";
}

Spring 会自动完成以下工作:

  1. 接收 HTTP 请求

  2. 解析 multipart/form-data

  3. 提取上传文件

  4. 封装成 MultipartFile

  5. 注入到 Controller 方法参数

整个过程开发者几乎无需额外处理。


二、文件上传流程

一次文件上传通常经历以下几个步骤:

复制代码
浏览器
    │
    │ 选择文件
    ▼
multipart/form-data 请求
    │
    ▼
DispatcherServlet
    │
    ▼
MultipartResolver
    │
    ▼
MultipartFile
    │
    ▼
Controller
    │
    ▼
保存到磁盘/数据库/OSS/MinIO

可以理解为:

浏览器负责发送文件。

SpringMVC 负责解析文件。

MultipartFile 负责保存文件信息。

开发者负责决定文件最终存放的位置。


三、Spring Boot 上传配置

Spring Boot 默认已经集成了文件上传功能,只需要配置上传大小即可。

复制代码
spring:
  servlet:
    multipart:
      enabled: true
      max-file-size: 10MB
      max-request-size: 20MB

参数说明:

配置项 说明
enabled 是否开启文件上传
max-file-size 单个文件最大大小
max-request-size 整个请求最大大小

例如:

一次上传:

复制代码
头像.jpg
2MB

允许上传。

如果上传:

复制代码
视频.mp4
50MB

则会抛出:

复制代码
MaxUploadSizeExceededException

四、MultipartFile 常用方法

Spring 提供了许多常用方法。

1、获取文件名

复制代码
String fileName = file.getOriginalFilename();

例如:

复制代码
photo.png

2、获取文件大小

复制代码
long size = file.getSize();

返回:

复制代码
204800

单位:

复制代码
Byte

3、获取文件类型

复制代码
String type = file.getContentType();

例如:

复制代码
image/png

image/jpeg

application/pdf

4、判断是否为空

复制代码
file.isEmpty();

开发中通常都会先判断:

复制代码
if(file.isEmpty()){
    return "文件不能为空";
}

5、获取输入流

复制代码
InputStream inputStream = file.getInputStream();

适用于:

  • 上传 OSS

  • 上传 MinIO

  • 上传七牛云

  • 上传腾讯 COS

因为这些云存储通常直接接收 InputStream。


6、保存文件

最常用的方法:

复制代码
file.transferTo(dest);

例如:

复制代码
File dest = new File("D:/upload/test.png");

file.transferTo(dest);

Spring 会自动完成文件复制。


五、实现单文件上传

Controller:

复制代码
@RestController
@RequestMapping("/file")
public class FileController {

    @PostMapping("/upload")
    public String upload(MultipartFile file) throws IOException {

        if(file.isEmpty()){
            return "文件为空";
        }

        File dir = new File("D:/upload");

        if(!dir.exists()){
            dir.mkdirs();
        }

        File dest = new File(dir,file.getOriginalFilename());

        file.transferTo(dest);

        return "上传成功";
    }

}

上传成功后:

复制代码
D:
    upload
        test.jpg

六、多文件上传

HTML:

复制代码
<input type="file" multiple>

Controller:

复制代码
@PostMapping("/uploads")
public String uploads(MultipartFile[] files) throws IOException {

    for (MultipartFile file : files) {

        if(file.isEmpty()){
            continue;
        }

        File dest = new File("D:/upload",file.getOriginalFilename());

        file.transferTo(dest);
    }

    return "success";
}

Spring 会自动封装多个文件。


七、防止文件重名

实际开发中不能直接使用原文件名。

例如:

用户 A:

复制代码
logo.png

用户 B:

复制代码
logo.png

第二次上传会覆盖第一次。

因此一般都会生成 UUID。

复制代码
String uuid = UUID.randomUUID().toString();

String suffix = file.getOriginalFilename()
                    .substring(file.getOriginalFilename().lastIndexOf("."));

String fileName = uuid + suffix;

生成:

复制代码
c9a22d1d-0b7d-4a31-a11d.png

这样可以避免文件名冲突。


八、文件类型校验

不能相信用户上传的数据。

例如:

有人可能把:

复制代码
病毒.exe

改成:

复制代码
图片.jpg

所以需要校验。

简单方式:

复制代码
String type = file.getContentType();

if(!type.startsWith("image/")){
    return "只能上传图片";
}

更严格的方式:

读取文件内容判断文件真实格式。

很多企业都会使用 Apache Tika 等工具进行检测。


九、文件大小校验

除了 Spring 配置限制。

代码里通常还会再次判断。

复制代码
if(file.getSize() > 5 * 1024 * 1024){
    return "文件不能超过5MB";
}

双重校验更加安全。


十、上传到服务器还是对象存储?

企业开发中一般有三种方式。

第一种:

保存到服务器本地。

复制代码
D:/upload

适用于:

  • 学习

  • 小项目

第二种:

保存到共享存储(NAS)。

多个服务器都可以访问。

第三种:

保存到对象存储。

例如:

  • 阿里云 OSS

  • MinIO

  • 腾讯云 COS

  • 七牛云 Kodo

这是目前企业最常见的方案。

优点:

  • 容量大

  • 支持 CDN

  • 支持权限控制

  • 便于扩容

  • 不占应用服务器磁盘


十一、MultipartFile 与 File 的区别

对比项 MultipartFile File
来源 Spring MVC Java IO
是否表示上传文件
是否依赖 Web 请求
是否能直接保存 可以 需要自己写流
使用场景 文件上传 本地文件操作

可以简单理解为:

  • MultipartFile 表示用户上传过程中的文件

  • File 表示服务器磁盘上的文件

在文件上传时,两者通常会配合使用:

复制代码
File dest = new File("D:/upload/test.png");

multipartFile.transferTo(dest);

MultipartFile 负责接收上传内容,File 负责表示保存目标。


十二、常见异常

1. 上传文件为空

原因:

未选择文件或上传失败。

解决:

复制代码
if(file.isEmpty()){
    return "请选择文件";
}

2. 文件超过限制

异常:

复制代码
MaxUploadSizeExceededException

解决:

调整 spring.servlet.multipart.max-file-sizemax-request-size 配置。


3. 保存路径不存在

原因:

目标目录未创建。

解决:

复制代码
File dir = new File("D:/upload");

if(!dir.exists()){
    dir.mkdirs();
}

4. 文件名为空

原因:

部分浏览器或客户端未正确传递文件名。

解决:

getOriginalFilename() 的返回值进行判空,并结合 UUID 生成新的文件名。


十三、面试高频问题

1. MultipartFile 是什么?

它是 Spring MVC 提供的文件上传接口,用于封装客户端上传的文件信息,开发者可以通过它获取文件名、大小、类型以及文件内容,并将文件保存到指定位置。

2. MultipartFileFile 有什么区别?

MultipartFile 表示 HTTP 请求中上传的文件,依赖于 Web 环境;File 是 Java IO 中表示文件或目录路径的对象,主要用于本地文件系统操作。

3. transferTo() 的作用是什么?

transferTo() 用于将上传文件保存到指定位置,底层会完成文件内容的写入,开发者无需手动编写输入输出流复制代码。

4. 为什么不能直接使用原文件名保存?

因为不同用户可能上传同名文件,直接保存会导致文件被覆盖。实际开发中通常使用 UUID、雪花算法或时间戳生成唯一文件名,并保留原始扩展名。

5. 企业项目中文件一般存在哪里?

大型项目通常不会将文件直接保存在应用服务器本地,而是存储到对象存储服务(如 OSS、MinIO、COS 等),既方便扩容,也便于结合 CDN 提升访问速度。


总结

MultipartFile 是 Spring MVC 文件上传功能的核心接口,它屏蔽了底层 HTTP 请求解析的复杂过程,使开发者能够专注于业务逻辑。实际开发中,一般会结合 UUID 防止文件重名、校验文件类型和大小,并根据项目规模选择本地存储或对象存储方案。掌握 MultipartFile 的使用流程和底层原理,不仅能够满足日常开发需求,也是 Java 后端面试中的常见考点。

相关推荐
程序员黑豆1 小时前
Java 注释详解:单行、多行与文档注释的完整指南
java·前端·ai编程
wuyk5553 小时前
第2章:六步换相原理全解+STM32工程实战
c语言·开发语言·stm32·单片机·嵌入式硬件
hey_sml3 小时前
JAVA每日一学---CompletableFuture中thenApply与thenCompose区别详解
java·开发语言
Doraemomo3 小时前
数据结构-环形链表
java·数据结构·链表
萧瑟余晖4 小时前
Java深入解析篇十七之SpringCloud
java·开发语言
是未才5 小时前
从输入 URL 到页面返回:DNS、路由、TLS 与 HTTP 完整链路
java·后端·计算机网络
ttod_qzstudio5 小时前
Java 常用语法极简通关(五):类与对象——字段、方法、构造器、this 与 static
java·开发语言·python
萧瑟余晖6 小时前
Java深入解析篇十七之Spring Security
java·开发语言·spring
不老刘7 小时前
【Java入门】Java服务部署方式全景对比:从java -jar到K8s
java·kubernetes·jar
离陌在学C#9 小时前
C# 重载与重写:深入理解面向对象编程的核心概念
java·c#