作者:不想打工的码农
标签:#Java #SpringBoot #文件上传 #后端开发 #实战技巧
大家好,我是老张。
上周三晚上10点,手机突然响了。
客户在电话那头急得直拍桌子:“老张!用户传个合同,系统直接报500!明天就要签单了啊!”
我赶紧远程连上服务器——
日志里赫然一行:org.apache.tomcat.util.http.fileupload.FileUploadBase $ SizeLimitExceededException: the request was rejected because its size exceeds the configured maximum

又是文件大小限制!
这已经是我今年第4次处理同类问题。
今天,我就把血泪总结的文件上传三板斧掏出来,手把手教你从0搭一个稳当的上传功能,连实习生都能看懂!
第一步:配置别乱改!认准这3个参数
很多教程让你改application.properties,但改错位置等于白改!
✅ 正确配置(Spring Boot 2.7+):
# 单个文件最大10MB(注意单位!)spring.servlet.multipart.max-file-size=10MB# 整个请求最大20MB(多个文件总和)spring.servlet.multipart.max-request-size=20MB# 上传超时时间(防大文件卡死)spring.servlet.multipart.request-timeout=30s⚠️ 血泪坑:
- 用spring.http.multipart?那是Spring Boot 1.x的老写法!2.x已废弃!
- 单位写成10M?必须带B(10MB),否则启动直接报错!
- 改完不重启?配置不会生效!(别笑,真有同事栽过)
第二步:Controller写法(带校验!)
直接上干货代码:
@PostMapping("/upload")public Result<String> uploadFile(@RequestParam("file") MultipartFile file) { // 1. 空文件校验 if (file.isEmpty()) { return Result.error(400, "文件不能为空"); } // 2. 类型校验(只允许PDF/Word) String originalFilename = file.getOriginalFilename(); String ext = originalFilename.substring(originalFilename.lastIndexOf(".") + 1).toLowerCase(); if (!Arrays.asList("pdf", "doc", "docx").contains(ext)) { return Result.error(400, "仅支持PDF、Word文档上传"); } // 3. 大小二次校验(防前端绕过) if (file.getSize() > 10 * 1024 * 1024) { // 10MB return Result.error(400, "文件大小不能超过10MB"); } // 4. 保存文件(关键!路径处理) String savePath = "/data/uploads/" + System.currentTimeMillis() + "_" + originalFilename; try { File dest = new File(savePath); // 确保目录存在 if (!dest.getParentFile().exists()) { dest.getParentFile().mkdirs(); } file.transferTo(dest); return Result.ok("上传成功,路径:" + savePath); } catch (IOException e) { log.error("文件保存失败", e); return Result.error(500, "服务器异常,请重试"); }}为什么校验写两遍?
- 前端校验能被绕过(F12改代码)
- 后端校验是最后防线,必须做!
第三步:前端配合(超简单)
<form id="uploadForm" enctype="multipart/form-data"> <input type="file" name="file" accept=".pdf,.doc,.docx" required> <button type="submit">上传</button></form><script>document.getElementById('uploadForm').onsubmit = function(e) { e.preventDefault(); const fileInput = this.querySelector('input[type="file"]'); const file = fileInput.files[0]; // 前端预校验(提升体验) if (file.size > 10 * 1024 * 1024) { alert("文件不能超过10MB!"); return; } const formData = new FormData(this); fetch('/api/upload', { method: 'POST', body: formData }) .then(res => res.json()) .then(data => alert(data.msg)) .catch(err => alert("上传失败"));};</script>✅ 关键细节:
- accept属性限制可选文件类型(但后端仍需校验!)
- 用FormData原生提交,不依赖jQuery
- 前端预校验提升用户体验,减少无效请求
避坑指南(全是实战踩出来的)
❌ 坑1:中文文件名乱码
现象:上传“合同_张三.pdf",保存成“????.pdf"
✅ 解决:
// 保存前对文件名编码(Linux服务器必加!)String safeName = URLEncoder.encode(originalFilename, "UTF-8").replace("+", "%20");❌ 坑2:Linux服务器没写入权限
现象:本地跑得好好的,上服务器就报Permission denied
✅ 解决:
# 上传前执行(给目录授权)chmod -R 755 /data/uploadschown -R www:www /data/uploads # 改成你的运行用户❌ 坑3:大文件上传超时
现象:传50MB文件,30秒后前端报“网络错误”
✅ 解决(三处都要改!):
# application.propertiesspring.servlet.multipart.request-timeout=300s# Nginx配置(/etc/nginx/conf.d/xxx.conf)client_max_body_size 100M;proxy_read_timeout 300s;❌ 坑4:路径写死导致迁移困难
✅ 最佳实践:
// 从配置读路径(方便不同环境切换)@Value(" $ {file.upload.path:/data/uploads}")private String uploadPath;最后说两句
文件上传看着简单,但90%的线上事故都出在细节上:
- 忘了二次校验 → 被传木马
- 路径没处理 → 服务器被写满
- 权限没配 → 客户急得跳脚
记住老张的话:
“前端校验是礼貌,后端校验是底线。”
把这三步做扎实,下次客户再打电话,你就能淡定回一句:
“稍等,我喝口茶就处理好。”
我是「不想打工的码农」,一个在代码和生活间找平衡的普通开发者。
觉得有用?点赞收藏防走丢!
评论区聊聊:你被文件上传坑过最惨的一次是啥?
#Java##SpringBoot##文件上传##后端开发##程序员避坑##不想打工的码农#程序员##职场##2026如何提振消费#