news 2026/7/29 13:42:16

Java WebUploader如何支持大文件分片上传的步骤解析?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java WebUploader如何支持大文件分片上传的步骤解析?

《大文件传输系统开发手记:一个老程序员的求生指南》


一、项目背景

最近接了个"地狱级"外包:客户要我用原生JS实现20G文件夹上传/下载,还要兼容IE9!我摸着所剩无几的头发,看着100元预算,陷入了沉思…

客户核心需求

  1. 支持20G文件夹上传(含1000级子目录)
  2. 断点续传(重启电脑都不能丢进度)
  3. SM4/AES加密传输+存储
  4. 非打包下载(几万文件秒传)
  5. 兼容IE9到Chrome全系列
  6. 预算100元(买杯咖啡都不够)

二、技术选型(穷人版)

前端方案
  • 原生JS+递归算法:手动实现文件夹树遍历
  • Web Workers:防止IE9卡死
  • Blob分片:把20G切成5MB小饼干
后端方案
  • SpringBoot:白嫖的Tomcat容器
  • MySQL:记录上传进度(穷人的Redis)
  • SM4算法:用BouncyCastle库(免费!)
加密方案
// 前端AES加密(兼容IE9)functionencryptAES(data,key){// 兼容IE9的crypto-js降级方案if(typeofCryptoJS==='undefined'){alert('请安装crypto-js插件!');returndata;}returnCryptoJS.AES.encrypt(data,key).toString();}

三、核心代码实现

1. 文件夹上传(原生JS版)
// 递归扫描文件夹(IE9兼容版)functionscanFolder(entry,pathMap){if(entry.isFile){entry.file(file=>{constrelativePath=pathMap.join('/')+'/'+file.name;uploadFile(file,relativePath);// 调用分片上传});}elseif(entry.isDirectory){constdirReader=entry.createReader();dirReader.readEntries(entries=>{constnewPath=[...pathMap,entry.name];entries.forEach(e=>scanFolder(e,newPath));});}}// 初始化文件夹选择(IE9兼容)document.getElementById('folderInput').addEventListener('change',e=>{constfiles=e.target.files;if(files.length===0)return;// IE9的特殊处理if(window.FileReader&&!window.FileEntry){alert('请使用Chrome/Firefox上传文件夹!');return;}// 现代浏览器if(files[0].webkitRelativePath){constrootPath=files[0].webkitRelativePath.split('/')[0];Array.from(files).forEach(file=>{constpath=file.webkitRelativePath.replace(rootPath,'');uploadFile(file,path);});}// 通过input[webkitdirectory]选择elseif(e.target.webkitEntries){Array.from(e.target.webkitEntries).forEach(entry=>{scanFolder(entry,[]);});}});
2. 分片上传(断点续传)
// 上传文件分片asyncfunctionuploadChunk(file,chunkIndex,totalChunks,filePath,fileId){constchunkSize=5*1024*1024;// 5MBconststart=chunkIndex*chunkSize;constend=Math.min(file.size,start+chunkSize);constchunk=file.slice(start,end);// 加密分片(SM4)constencrypted=awaitencryptSM4(chunk,'1234567890abcdef');// 实际应从后端获取密钥returnfetch('/api/upload',{method:'POST',body:encrypted,headers:{'X-File-ID':fileId,'X-Chunk-Index':chunkIndex,'X-Total-Chunks':totalChunks,'X-File-Path':filePath}}).then(res=>res.json());}// 进度持久化(localStorage+IndexedDB双备份)functionsaveProgress(fileId,progress){try{// IE9兼容方案if(window.localStorage){localStorage.setItem(`progress_${fileId}`,JSON.stringify(progress));}// 现代浏览器用IndexedDBif(window.indexedDB){constrequest=indexedDB.open('FileProgressDB',1);request.onsuccess=()=>{constdb=request.result;consttx=db.transaction('progress','readwrite');conststore=tx.objectStore('progress');store.put(progress,fileId);};}}catch(e){console.error('进度保存失败:',e);}}
3. SpringBoot后端(穷人版)
@RestController@RequestMapping("/api")publicclassFileController{@Value("${file.storage.path}")privateStringstoragePath;// 分片上传接口@PostMapping("/upload")publicResponseEntityuploadChunk(@RequestParam("file")MultipartFilefile,@RequestHeader("X-File-ID")StringfileId,@RequestHeader("X-Chunk-Index")intchunkIndex,@RequestHeader("X-Total-Chunks")inttotalChunks,@RequestHeader("X-File-Path")StringfilePath){try{// 解密文件(SM4)byte[]decrypted=decryptSM4(file.getBytes(),"1234567890abcdef");// 保存分片StringchunkPath=storagePath+"/"+fileId+"/chunks/"+chunkIndex;Files.createDirectories(Paths.get(chunkPath).getParent());Files.write(Paths.get(chunkPath),decrypted);// 更新进度到MySQLupdateProgress(fileId,chunkIndex,totalChunks,filePath);returnResponseEntity.ok().body(Map.of("success",true));}catch(Exceptione){returnResponseEntity.status(500).body(Map.of("error",e.getMessage()));}}// 合并文件(伪代码)@GetMapping("/merge")publicResponseEntitymergeFile(@RequestParamStringfileId){// 1. 从MySQL查询所有分片信息// 2. 按顺序合并到最终文件// 3. 删除分片目录// 4. 返回下载URLreturnResponseEntity.ok().body(Map.of("url","/download/"+fileId));}}

四、兼容性黑科技

1. IE9兼容方案
2. 文件夹上传降级方案
// 如果浏览器不支持文件夹上传,提示用户压缩成ZIPfunctioncheckFolderSupport(){if(!window.File&&!window.FileReader&&!window.FileList&&!window.Blob){alert('您的浏览器太古老了!请:\n1. 使用Chrome/Firefox\n2. 或把文件夹压缩成ZIP上传');}}

五、部署指南(白嫖版)

  1. 服务器配置

    • 买台1核2G的云服务器(阿里云学生机9.9元/月)
    • 安装Tomcat + MySQL
  2. 编译打包

    # 前端打包npmrun build# 后端打包mvn clean package# 手动复制dist目录到Tomcat的webappscp-r dist/* /var/lib/tomcat9/webapps/ROOT/
  3. MySQL初始化

CREATETABLEfile_progress(idVARCHAR(64)PRIMARYKEY,file_pathVARCHAR(512)NOTNULL,total_chunksINTNOTNULL,received_chunksINTDEFAULT0,last_updateTIMESTAMPDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMP);

六、项目总结

  1. 成果:用100元预算实现了20G文件夹上传!
  2. 代价:头发又少了100根…
  3. 建议:下次接单前先看牙医(防止气到咬碎后槽牙)

最终解决方案

  • 前端代码:GitHub链接
  • 后端代码:附在邮件压缩包里
  • 交流群:374992201(加群领红包!)

温馨提示:本项目仅供学习交流,如需商用请自行购买商业授权(虽然我根本没卖…)

导入项目

导入到Eclipse:点南查看教程
导入到IDEA:点击查看教程
springboot统一配置:点击查看教程

工程

NOSQL

NOSQL示例不需要任何配置,可以直接访问测试

创建数据表

选择对应的数据表脚本,这里以SQL为例

修改数据库连接信息

访问页面进行测试

文件存储路径

up6/upload/年/月/日/guid/filename

效果预览

文件上传

文件刷新续传

支持离线保存文件进度,在关闭浏览器,刷新浏览器后进行不丢失,仍然能够继续上传

文件夹上传

支持上传文件夹并保留层级结构,同样支持进度信息离线保存,刷新页面,关闭页面,重启系统不丢失上传进度。

下载示例

点击下载完整示例

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/28 20:34:13

【AI框架部署避坑宝典】:Open-AutoGLM安装失败的7种真实场景与修复方案

第一章:Open-AutoGLM安装失败的典型现象与诊断思路在部署 Open-AutoGLM 时,用户常遇到安装中断、依赖冲突或环境不兼容等问题。这些故障通常表现为包下载失败、编译错误或运行时模块缺失。正确识别现象并建立系统化诊断流程是解决问题的关键。常见安装异…

作者头像 李华
网站建设 2026/7/28 7:32:58

Linly-Talker在垃圾焚烧发电厂的环保指标说明

Linly-Talker在垃圾焚烧发电厂的环保指标说明 在“双碳”目标持续推进的今天,垃圾焚烧发电作为城市固废处理的关键环节,正面临前所未有的公众关注。烟囱是否排“毒气”?二噁英真的能控制住吗?这些高频问题背后,折射出…

作者头像 李华
网站建设 2026/7/28 2:47:12

Linly-Talker在体育赛事直播中的激情解说

Linly-Talker:当AI数字人点燃体育赛事解说的激情 在一场关键的足球决赛中,第89分钟,主队球员突入禁区、一脚劲射破门!全场沸腾。就在进球发生的瞬间,直播画面中一位神情激昂的虚拟解说员猛然站起,挥拳呐喊&…

作者头像 李华
网站建设 2026/7/28 11:29:40

英语考研小作文轮椅流(基于Fiona的英语美食)

因为小作文中介绍信、建议信、推荐信考频较高,所以优先做三合一模版.小作文没什么好花里胡哨的,格式能对就成功大半了。本模版按我的习惯采取缩进式。其实不管是推荐、建议还是介绍,基本是对方先有需求或者假定了对方一个需求写的&#xff0c…

作者头像 李华
网站建设 2026/7/28 13:25:32

vue3+springboot基于微信的校园跑腿系统 小程序的设计与实现(编号:49659506)

文章目录具体实现截图主要技术与实现手段关于我本系统开发思路java类核心代码部分展示结论源码lw获取/同行可拿货,招校园代理 :文章底部获取博主联系方式!具体实现截图 同行可拿货,招校园代理 vue3springboot基于微信的校园跑腿系统 小程序的设计与实…

作者头像 李华
网站建设 2026/7/28 19:00:13

Linly-Talker在林业资源保护中的盗伐警告

Linly-Talker:用“数字护林员”守护绿水青山 在云南哀牢山深处的一片原始林区,夜色正浓。一阵轻微的震动被埋设在地下的传感器捕捉到——有人携带工具进入禁伐区。几秒后,树冠间隐藏的扬声器传出一声低沉而严肃的警告:“你已进入国…

作者头像 李华