前言
在后台管理系统中,文件上传也是一个非常常见的功能。
比如员工头像上传、文章封面上传、商品图片上传、资料附件上传等,都需要后端提供文件上传接口。
这一篇我们来学习 Spring Boot 中如何使用 MultipartFile 实现文件上传。
一、文件上传的基本流程
文件上传的大致流程是:
前端选择文件
↓
发送 multipart/form-data 请求
↓
后端使用 MultipartFile 接收文件
↓
生成新的文件名
↓
保存到服务器指定目录
↓
返回文件访问路径
后端接口一般接收的不是 JSON,而是表单文件数据。
二、Controller 层实现
@RestController
public class UploadController {
@PostMapping("/upload")
public Result upload(MultipartFile image) throws IOException {
String originalFilename = image.getOriginalFilename();
String extName = originalFilename.substring(originalFilename.lastIndexOf("."));
String newFileName = UUID.randomUUID().toString() + extName;
image.transferTo(new File("D:/upload/" + newFileName));
String url = "/upload/" + newFileName;
return Result.success(url);
}
}
文字说明
这里使用:
MultipartFile image
接收前端上传的文件。
getOriginalFilename() 可以获取原始文件名,比如:
avatar.png
为了避免文件名重复,我们使用:
UUID.randomUUID()
生成新的文件名。
最后通过:
image.transferTo()
把文件保存到指定目录。
三、为什么要重命名文件?
如果直接使用原始文件名保存,可能会出现覆盖问题。
比如两个用户都上传:
avatar.png
如果都保存成这个名字,后上传的文件可能会覆盖前一个文件。
所以更推荐使用 UUID 生成唯一文件名:
7a9f62c8-3c79-4b7d-91c8-b61d0b6f9e8a.png
这样可以大大降低文件名重复的概率。
四、配置文件上传大小
Spring Boot 默认对上传文件大小有限制,如果文件太大,可能会上传失败。
可以在 application.yml 中配置:
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 100MB
说明:
max-file-size:单个文件最大大小
max-request-size:单次请求最大大小
五、Service 层要不要写?
如果只是简单上传到本地,Controller 里直接处理也可以。
但如果上传逻辑变复杂,比如要上传到阿里云 OSS、保存文件记录到数据库、校验文件类型,就建议抽到 Service 层。
1. Controller 层
@RestController
public class UploadController {
@Autowired
private UploadService uploadService;
@PostMapping("/upload")
public Result upload(MultipartFile image) throws IOException {
String url = uploadService.upload(image);
return Result.success(url);
}
}
2. Service 层
public interface UploadService {
String upload(MultipartFile image) throws IOException;
}
@Service
public class UploadServiceImpl implements UploadService {
@Override
public String upload(MultipartFile image) throws IOException {
String originalFilename = image.getOriginalFilename();
String extName = originalFilename.substring(originalFilename.lastIndexOf("."));
String newFileName = UUID.randomUUID().toString() + extName;
File dir = new File("D:/upload/");
if (!dir.exists()) {
dir.mkdirs();
}
image.transferTo(new File(dir, newFileName));
return "/upload/" + newFileName;
}
}
文字说明
这样写之后,Controller 只负责接收请求和返回结果,真正的文件保存逻辑放到 Service 层。
如果以后要把本地上传改成云存储,只需要改 Service 层,Controller 基本不用动。
六、常见问题
1. 前端字段名要和后端参数名一致
后端写的是:
MultipartFile image
那么前端上传时字段名也应该是:
image
如果字段名不一致,后端可能接收不到文件。
2. 上传目录不存在会报错
如果保存路径不存在,可能会上传失败。
所以建议保存前先判断目录是否存在:
if (!dir.exists()) {
dir.mkdirs();
}
3. 不要完全相信文件后缀名
用户上传的文件后缀不一定可靠。
真实项目中,建议校验文件大小、文件类型,并限制只能上传图片、文档等指定类型。
七、实际开发建议
文件上传接口建议注意下面几点:
八、总结
这一篇主要学习了 Spring Boot 中使用 MultipartFile 实现文件上传。
文件上传的核心是:前端使用 multipart/form-data 提交文件,后端使用 MultipartFile 接收文件,再通过 transferTo() 保存文件。
简单上传可以直接写在 Controller 中,复杂上传建议拆到 Service 层。这样后期如果要切换到云存储,也会更方便。
到这里,Spring Boot + MyBatis 知识点系列的第一组核心内容就基本完成了。它们分别覆盖了接口开发、参数接收、统一返回、动态 SQL、分页、异常处理、登录认证和文件上传,基本可以支撑一个完整后台项目的开发。
