深浅模式
文件上传,就是把本地的图片、音频、视频等文件,通过前端页面发送到服务器,方便后续的存储和访问。
要实现这样一个功能,本质上只需要三个环节:
- 前端:构建能正确提交文件的页面;
- 后端:编写接口接收并处理文件;
- 存储:把接收到的文件保存到本地或云端。
前端与后端各有关键要素,而存储实现上,我们会分别实现 本地上传 和 云存储 两种方式。
前端传递
文件上传的前端实现,关键只要三样到位:
- 必须使用
type="file"的控件,这样用户才能从本地选择文件。 - 请求方式必须是
POST,因为GET请求无法承载二进制文件内容。 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 把文件流上传到云端。
典型步骤如下:
- 申请 AccessKey(用来授权访问 OSS);
- 创建 Bucket(相当于一个文件夹);
- 使用 SDK 上传文件流;
- 返回文件的公网访问地址。
代码结构示例:
java
@Data
@AllArgsConstructor
@Slf4j
public class AliOssUtil {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
/**
* 文件上传
*
* @param bytes
* @param objectName
* @return
*/
public String upload(byte[] bytes, String objectName) {
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
// 创建PutObject请求。
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
//文件访问路径规则 https://BucketName.Endpoint/ObjectName StringBuilder stringBuilder = new StringBuilder("https://");
stringBuilder
.append(bucketName)
.append(".")
.append(endpoint)
.append("/")
.append(objectName);
log.info("文件上传到:{}", stringBuilder.toString());
return stringBuilder.toString();
}
}这样一来,文件就不会再依赖本地磁盘,而是被存进云端。
只要有外链,任何人都能直接访问这份文件,不用占用你的服务器空间。

评论