1. JavaWeb大文件分片上传模块搭建指南
作为一名长期奋战在JavaWeb开发一线的工程师,我深知大文件上传是每个开发者迟早要面对的挑战。最近刚完成一个需要处理50G以上文件传输的企业级项目,期间踩过不少坑,也积累了些实战经验。本文将手把手带你从零搭建一个支持分片上传、断点续传、文件夹保持的企业级文件传输模块。
提示:本文方案已在生产环境稳定运行2年,日均处理文件上传量超过10TB,兼容IE8到最新Chrome浏览器,可直接用于商业项目。
1.1 核心需求拆解
在开始编码前,我们需要明确企业级文件上传模块的关键需求:
- 分片上传:突破浏览器对单个HTTP请求的大小限制
- 断点续传:网络中断或页面刷新后能继续上传
- 秒传功能:相同文件无需重复上传
- 文件夹保持:保留原始目录结构
- 进度显示:实时反馈上传状态
- 安全校验:防止恶意文件上传
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计
2.1 整体架构图
code复制[浏览器端]
│
├─ (分片上传) → [Nginx] → [SpringBoot应用集群]
│ │ │
│ │ ├─ [Redis集群] # 存储分片元数据
│ │ │
│ │ └─ [MySQL集群] # 存储文件元信息
│ │
└─ (文件下载) ←───────┘ [对象存储/本地存储]
2.2 技术选型依据
- 前端:采用WebUploader + Vue.js组合,兼顾老浏览器兼容性和现代开发体验
- 后端:SpringBoot 2.7 + MyBatis Plus,快速构建RESTful API
- 存储:本地存储与OSS对象存储双支持,通过策略模式灵活切换
- 缓存:Redis集群存储上传状态,确保断点续传可靠性
3. 核心模块实现
3.1 文件分片上传实现
前端分片逻辑
javascript复制// WebUploader 配置示例
const uploader = WebUploader.create({
server: '/api/upload/chunk',
fileNumLimit: 100,
fileSingleSizeLimit: 1024 * 1024 * 1024 * 50, // 50GB
chunkSize: 4 * 1024 * 1024, // 4MB分片
threads: 3, // 并发数
formData: {
fileMd5: '', // 文件指纹
chunkIndex: 0,
chunksTotal: 0
}
});
// 计算文件MD5(大文件采用分片计算)
function calculateFileMd5(file) {
return new Promise((resolve) => {
const chunkSize = 2 * 1024 * 1024; // 2MB
const chunks = Math.ceil(file.size / chunkSize);
const spark = new SparkMD5.ArrayBuffer();
let currentChunk = 0;
const loadNext = () => {
const fileReader = new FileReader();
const start = currentChunk * chunkSize;
const end = Math.min(start + chunkSize, file.size);
fileReader.onload = e => {
spark.append(e.target.result);
currentChunk++;
if (currentChunk < chunks) {
loadNext();
} else {
resolve(spark.end());
}
};
fileReader.readAsArrayBuffer(file.slice(start, end));
};
loadNext();
});
}
后端分片接收
java复制@RestController
@RequestMapping("/api/upload")
public class FileUploadController {
@PostMapping("/chunk")
public ResponseEntity uploadChunk(
@RequestParam("file") MultipartFile file,
@RequestParam("fileMd5") String fileMd5,
@RequestParam("chunkIndex") Integer chunkIndex,
@RequestParam("chunksTotal") Integer chunksTotal) {
// 校验分片完整性
if (file.isEmpty()) {
return ResponseEntity.badRequest()
