Skip to content

文件上传


文件上传,就是把本地的图片、音频、视频等文件,通过前端页面发送到服务器,方便后续的存储和访问。

要实现这样一个功能,本质上只需要三个环节:

  • 前端:构建能正确提交文件的页面;
  • 后端:编写接口接收并处理文件;
  • 存储:把接收到的文件保存到本地或云端。

前端与后端各有关键要素,而存储实现上,我们会分别实现 本地上传OSS 云存储 两种方式。

前端传递

文件上传的前端实现,关键只要三样到位:

  1. 必须使用 type="file" 的控件,这样用户才能从本地选择文件。
  2. 请求方式必须是 POST,因为 GET 请求无法承载二进制文件内容。
  3. enctype 必须设置为 multipart/form-data,否则后端根本收不到文件。

一个最基础的上传表单示例 👇

html
<form action="/upload" method="post" enctype="multipart/form-data">
  名字:<input type="text" name="userName"><br>
  年龄:<input type="text" name="userAge"><br>
  头像:<input type="file" name="avatar"><br>
  <input type="submit" value="提交">
</form>

选中文件后,浏览器会在提交时将文本字段与文件内容一并打包发送给后端。
只要这三件事做到位,后端接口就能顺利接收到文件。

后端接收

前端表单提交之后,后端必须有一个接口能把这份请求“接住”。
在 Spring Boot 里,处理文件上传最常用的方式就是使用 MultipartFile。它不仅能接收文件本身,也能同时接收普通的文本字段

java
@RestController
public class UploadController {

    @PostMapping("/upload")
    public Result upload(String userName, Integer userAge, MultipartFile avatar) {
        log.info("收到上传请求:名字 = {}, 年龄 = {}, 文件 = {}", userName, userAge, avatar);
        return Result.success();
    }
}

这里的 MultipartFile 会自动映射前端上传的文件内容。
参数名必须和前端的 name 属性保持一致,比如表单中是 avatar,方法参数也得是 avatar,否则就接收不到。

这样,一个最简单的“上传请求”闭环就打通了。

本地存储

文件上传到后端后,如果只是为了让服务器本身能读取和访问这些文件,最简单的方式就是直接存到本地磁盘

Spring Boot 已经为我们封装好了常用方法,MultipartFile 提供的 transferTo() 就能把上传的文件保存下来:

java
@PostMapping("/upload")
public Result upload(String userName, Integer userAge, MultipartFile avatar) throws Exception {

    // 获取原始文件名,然后截取文件后缀
    String originalFilename = avatar.getOriginalFilename(); // 例如:001.jpg
    String suffix = originalFilename.substring(originalFilename.lastIndexOf(".")); // .jpg

    // 生成随机文件名,避免覆盖
    String newFileName = UUID.randomUUID().toString() + suffix;

    // 构建存储路径(这里用 D 盘举例)
    File dest = new File("D:/upload_test/" + newFileName);

    // 6. 保存文件
    avatar.transferTo(dest);

    return Result.success("文件已保存:" + dest.getAbsolutePath());
}

这段代码的核心就两步:

  • 获取文件原始信息(名字、后缀);
  • 转成新文件名然后 transferTo() 存进去。

如果你直接用原始名称存,多个用户上传同名文件时会互相覆盖,所以实际开发中都会用 UUID 生成一个唯一的名字,再拼上原始的后缀。

上传大小限制

Spring Boot 默认的单文件上传大小只有 1MB,如果超了,就会直接报错,例如:

The field avatar exceeds its maximum permitted size of 1048576 bytes.

解决方式很简单,只要在 application.properties 里改配置就行:

properties
# 单个文件最大 10MB
spring.servlet.multipart.max-file-size=10MB

# 单次请求最大 100MB(比如一次上传多个文件)
spring.servlet.multipart.max-request-size=100MB

配置好后,transferTo() 就能轻松保存更大的文件了。

云端存储:传到 OSS

在项目部署到云服务器后,本地磁盘存文件就不太合适了:

用 阿里云 OSS 这种对象存储服务会更合适。它本质上就是一个更稳定、更安全的“远程文件仓库”,可以随时上传、下载、外链访问。

实现流程和本地存储几乎一样,区别只在于最后这一步不再是 transferTo(),而是通过 OSS SDK 把文件流上传到云端。

典型步骤如下 👇

  1. 申请 AccessKey(用来授权访问 OSS);
  2. 创建 Bucket(相当于一个文件夹);
  3. 使用 SDK 上传文件流;
  4. 返回文件的公网访问地址。

代码结构示例 👇

java
// 生成唯一文件名
String originalFilename = avatar.getOriginalFilename();
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
String newFileName = UUID.randomUUID().toString() + suffix;

// 上传到 OSS
String fileUrl = ossClient.putObject(bucketName, newFileName, avatar.getInputStream());

// 返回外链
return Result.success(fileUrl);

这样一来,文件就不会再依赖本地磁盘,而是被存进云端。
只要有外链,任何人都能直接访问这份文件,不用占用你的服务器空间。

评论