2026/2/18 20:02:13
网站建设
项目流程
建设个人网站用到的技术,seo教育培训机构,网站建设课程设计目的和内容,哪里有做证《大文件传输系统开发手记#xff1a;一个老程序员的求生指南》 一、项目背景
最近接了个地狱级外包#xff1a;客户要我用原生JS实现20G文件夹上传/下载#xff0c;还要兼容IE9#xff01;我摸着所剩无几的头发#xff0c;看着100元预算#xff0c;陷入了沉…《大文件传输系统开发手记一个老程序员的求生指南》一、项目背景最近接了个地狱级外包客户要我用原生JS实现20G文件夹上传/下载还要兼容IE9我摸着所剩无几的头发看着100元预算陷入了沉思…客户核心需求支持20G文件夹上传含1000级子目录断点续传重启电脑都不能丢进度SM4/AES加密传输存储非打包下载几万文件秒传兼容IE9到Chrome全系列预算100元买杯咖啡都不够二、技术选型穷人版前端方案原生JS递归算法手动实现文件夹树遍历Web Workers防止IE9卡死Blob分片把20G切成5MB小饼干后端方案SpringBoot白嫖的Tomcat容器MySQL记录上传进度穷人的RedisSM4算法用BouncyCastle库免费加密方案// 前端AES加密兼容IE9functionencryptAES(data,key){// 兼容IE9的crypto-js降级方案if(typeofCryptoJSundefined){alert(请安装crypto-js插件);returndata;}returnCryptoJS.AES.encrypt(data,key).toString();}三、核心代码实现1. 文件夹上传原生JS版// 递归扫描文件夹IE9兼容版functionscanFolder(entry,pathMap){if(entry.isFile){entry.file(file{constrelativePathpathMap.join(/)/file.name;uploadFile(file,relativePath);// 调用分片上传});}elseif(entry.isDirectory){constdirReaderentry.createReader();dirReader.readEntries(entries{constnewPath[...pathMap,entry.name];entries.forEach(escanFolder(e,newPath));});}}// 初始化文件夹选择IE9兼容document.getElementById(folderInput).addEventListener(change,e{constfilese.target.files;if(files.length0)return;// IE9的特殊处理if(window.FileReader!window.FileEntry){alert(请使用Chrome/Firefox上传文件夹);return;}// 现代浏览器if(files[0].webkitRelativePath){constrootPathfiles[0].webkitRelativePath.split(/)[0];Array.from(files).forEach(file{constpathfile.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){constchunkSize5*1024*1024;// 5MBconststartchunkIndex*chunkSize;constendMath.min(file.size,startchunkSize);constchunkfile.slice(start,end);// 加密分片SM4constencryptedawaitencryptSM4(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(resres.json());}// 进度持久化localStorageIndexedDB双备份functionsaveProgress(fileId,progress){try{// IE9兼容方案if(window.localStorage){localStorage.setItem(progress_${fileId},JSON.stringify(progress));}// 现代浏览器用IndexedDBif(window.indexedDB){constrequestindexedDB.open(FileProgressDB,1);request.onsuccess(){constdbrequest.result;consttxdb.transaction(progress,readwrite);conststoretx.objectStore(progress);store.put(progress,fileId);};}}catch(e){console.error(进度保存失败:,e);}}3. SpringBoot后端穷人版RestControllerRequestMapping(/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{// 解密文件SM4byte[]decrypteddecryptSM4(file.getBytes(),1234567890abcdef);// 保存分片StringchunkPathstoragePath/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核2G的云服务器阿里云学生机9.9元/月安装Tomcat MySQL编译打包# 前端打包npmrun build# 后端打包mvn clean package# 手动复制dist目录到Tomcat的webappscp-r dist/* /var/lib/tomcat9/webapps/ROOT/MySQL初始化CREATETABLEfile_progress(idVARCHAR(64)PRIMARYKEY,file_pathVARCHAR(512)NOTNULL,total_chunksINTNOTNULL,received_chunksINTDEFAULT0,last_updateTIMESTAMPDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMP);六、项目总结成果用100元预算实现了20G文件夹上传代价头发又少了100根…建议下次接单前先看牙医防止气到咬碎后槽牙最终解决方案前端代码GitHub链接后端代码附在邮件压缩包里交流群374992201加群领红包温馨提示本项目仅供学习交流如需商用请自行购买商业授权虽然我根本没卖…导入项目导入到Eclipse点南查看教程导入到IDEA点击查看教程springboot统一配置点击查看教程工程NOSQLNOSQL示例不需要任何配置可以直接访问测试创建数据表选择对应的数据表脚本这里以SQL为例修改数据库连接信息访问页面进行测试文件存储路径up6/upload/年/月/日/guid/filename效果预览文件上传文件刷新续传支持离线保存文件进度在关闭浏览器刷新浏览器后进行不丢失仍然能够继续上传文件夹上传支持上传文件夹并保留层级结构同样支持进度信息离线保存刷新页面关闭页面重启系统不丢失上传进度。下载示例点击下载完整示例