📌毕业设计求生指南:大文件上传系统(兼容IE8版)
😩 现状描述
大家好,我是浙江某三本计算机专业的大三学生,马上要毕业了,现在被导师逼着搞一个**「支持10G文件上传的系统」**,要求如下:
- 必须用原生JS(不能用jQuery等库)
- 支持IE8及国产浏览器(龙芯、红莲花、奇安信)
- 支持文件夹上传(保留层级结构)
- 断点续传(重启电脑也不能丢进度)
- 加密传输+存储(AES/SM4)
- 后端用SpringBoot(我Java还没学透)
- 前端用Vue3(但导师说IE8不支持,让我用原生JS)
- 对象存储用阿里云OSS(但学校服务器是本地CentOS虚拟机)
💢 最气的是:网上找的代码要么只能传5MB小文件,要么文件夹上传是残废的,最离谱的是作者连个联系方式都不留,出了问题只能对着屏幕喊**「爸爸救我」**……
💡 解决方案(抄作业版)
🖥️ 前端部分(原生JS + 兼容IE8)
1. 文件选择与文件夹上传(兼容IE8)
// FileUploader.js(兼容IE8的魔改版)functionFileUploader(containerId,config){this.config=Object.assign({chunkSize:5*1024*1024,// 5MB分片maxRetry:3,encrypt:true},config);// 检测浏览器类型(IE8特殊处理)this.isIE8=!!window.ActiveXObject&&!document.addEventListener;// 初始化UIthis.initUI(containerId);}FileUploader.prototype.initUI=function(containerId){constcontainer=document.getElementById(containerId);container.innerHTML=`开始上传`;// IE8用Flash模拟文件夹选择(伪代码)if(this.isIE8){this.setupIE8Fallback();}// 绑定事件document.getElementById('startBtn').addEventListener('click',()=>{constfiles=document.getElementById('fileInput').files;this.handleFiles(files);});};// 处理文件(支持文件夹层级)FileUploader.prototype.handleFiles=function(files){constfileTree={};// 遍历文件,构建层级结构for(leti=0;i<files.length;i++){constfile=files[i];constpath=this.isIE8?file.name:file.webkitRelativePath;constparts=path.split('/');letcurrent=fileTree;for(letj=0;j<parts.length-1;j++){constdir=parts[j];if(!current[dir]){current[dir]={};}current=current[dir];}current[parts[parts.length-1]]=file;}// 开始上传this.uploadFileTree(fileTree);};2. 分片上传 + 断点续传(支持离线保存进度)
// 分片上传核心逻辑FileUploader.prototype.uploadFile=function(file,relativePath=''){constfileId=this.generateFileId(file);consttotalChunks=Math.ceil(file.size/this.config.chunkSize);letcurrentChunk=0;// 从本地存储加载进度constsavedProgress=this.loadProgress(fileId);if(savedProgress){currentChunk=savedProgress.currentChunk;}constuploadChunk=()=>{if(currentChunk>=totalChunks){this.onUploadComplete(fileId,relativePath);return;}conststart=currentChunk*this.config.chunkSize;constend=Math.min(start+this.config.chunkSize,file.size);constchunk=file.slice(start,end);// 加密处理(伪代码)letencryptedChunk=chunk;if(this.config.encrypt){encryptedChunk=this.encryptData(chunk);// 实际要用SM4/AES库}constformData=newFormData();formData.append('fileId',fileId);formData.append('chunkIndex',currentChunk);formData.append('totalChunks',totalChunks);formData.append('relativePath',relativePath);formData.append('file',newBlob([encryptedChunk]));// 发送请求(兼容IE8的XMLHttpRequest)constxhr=this.createXHR();xhr.open('POST','/api/upload',true);xhr.onload=()=>{if(xhr.status===200){currentChunk++;// 保存进度到localStoragethis.saveProgress(fileId,{currentChunk,totalChunks,fileName:file.name,relativePath});uploadChunk();}else{// 重试机制if(this.retryCount<this.config.maxRetry){this.retryCount++;setTimeout(uploadChunk,1000);}}};xhr.send(formData);};uploadChunk();};// 兼容IE8的XHR创建FileUploader.prototype.createXHR=function(){try{returnnewXMLHttpRequest();}catch(e){try{returnnewActiveXObject('Msxml2.XMLHTTP');}catch(e){returnnewActiveXObject('Microsoft.XMLHTTP');}}};3. 断点续传持久化(localStorage + IE8降级方案)
// 保存上传进度FileUploader.prototype.saveProgress=function(fileId,progress){try{if(window.localStorage){localStorage.setItem(`upload_${fileId}`,JSON.stringify(progress));}else{// IE7及以下用userData存储(更古老的方案)this.saveToUserData(fileId,progress);}}catch(e){console.error('保存进度失败:',e);}};// 加载上传进度FileUploader.prototype.loadProgress=function(fileId){try{if(window.localStorage){constdata=localStorage.getItem(`upload_${fileId}`);returndata?JSON.parse(data):null;}// IE7及以下方案...}catch(e){console.error('加载进度失败:',e);returnnull;}};🛠️ 后端部分(SpringBoot)
1. 文件分片接收控制器
@RestController@RequestMapping("/api/upload")publicclassFileUploadController{@Value("${oss.endpoint}")privateStringossEndpoint;@PostMappingpublicResponseEntityhandleFileUpload(@RequestParam("fileId")StringfileId,@RequestParam("chunkIndex")intchunkIndex,@RequestParam("totalChunks")inttotalChunks,@RequestParam("relativePath")StringrelativePath,@RequestParam("file")MultipartFilefile){try{// 1. 验证分片(防止恶意上传)if(chunkIndex<0||chunkIndex>=totalChunks){returnResponseEntity.badRequest().body("Invalid chunk index");}// 2. 保存到临时目录(实际项目用OSS)PathtempDir=Paths.get(System.getProperty("java.io.tmpdir"),"uploads",fileId);Files.createDirectories(tempDir);PathchunkPath=tempDir.resolve(chunkIndex+".part");Files.write(chunkPath,file.getBytes(),StandardOpenOption.CREATE);// 3. 如果是最后一个分片,合并文件if(chunkIndex==totalChunks-1){mergeFile(fileId,tempDir,totalChunks,relativePath);}returnResponseEntity.ok("Chunk uploaded successfully");}catch(Exceptione){returnResponseEntity.status(500).body("Upload failed: "+e.getMessage());}}privatevoidmergeFile(StringfileId,PathtempDir,inttotalChunks,StringrelativePath)throwsIOException{PathoutputPath=Paths.get(System.getProperty("java.io.tmpdir"),"uploads",fileId+".dat");try(OutputStreamout=Files.newOutputStream(outputPath,StandardOpenOption.CREATE)){for(inti=0;i<totalChunks;i++){PathchunkPath=tempDir.resolve(i+".part");Files.copy(chunkPath,out);Files.delete(chunkPath);// 清理分片}}// TODO: 上传到OSS并加密存储}}2. 加密存储服务(SM4示例)
@ServicepublicclassCryptoService{// 使用BouncyCastle实现SM4(实际项目需要引入依赖)publicbyte[]encryptSM4(byte[]data,byte[]key)throwsException{SM4Engineengine=newSM4Engine();BufferedBlockCiphercipher=newPaddedBufferedBlockCipher(newCBCBlockCipher(engine));cipher.init(true,newParametersWithIV(newKeyParameter(key),newbyte[16]));byte[]output=newbyte[cipher.getOutputSize(data.length)];intbytesWritten=cipher.processBytes(data,0,data.length,output,0);bytesWritten+=cipher.doFinal(output,bytesWritten);returnArrays.copyOf(output,bytesWritten);}}🎯 生存指南
IE8兼容性:
- 用Flash作为降级方案(虽然很古老但有效)
- 避免使用ES6+语法(用Babel转译)
- 测试用Windows 7 + IE9虚拟机(学校机房同款)
大文件上传技巧:
- 分片大小控制在5-10MB
- 使用Web Worker处理加密(避免UI卡顿)
- 服务器端验证分片完整性
找工作秘籍:
- 把毕业设计包装成「企业级文件传输系统」
- 重点强调「兼容信创环境」(国企/银行很吃这套)
- 在GitHub挂个Demo(记得把测试账号密码写进README)
📢 最后吐槽:求各位大佬加群374992201啊!送红包是假的,但找工作互助是真的!群里还有大佬在阿里云/华为上班,说不定能内推呢~(群文件有完整项目代码和SQL脚本)
🚀 完整代码获取方式
- 加QQ群:374992201(送1~99元红包)
- GitHub:https://github.com/your-repo/file-uploader(待补充)
- 直接联系作者:QQ/微信在群公告
🙏 跪求大佬指导!毕业答辩就靠这个了!
导入项目
导入到Eclipse:点击查看教程
导入到IDEA:点击查看教程
springboot统一配置:点击查看教程
工程
NOSQL
NOSQL示例不需要任何配置,可以直接访问测试
创建数据表
选择对应的数据表脚本,这里以SQL为例
修改数据库连接信息
访问页面进行测试
文件存储路径
up6/upload/年/月/日/guid/filename
效果预览
文件上传
文件刷新续传
支持离线保存文件进度,在关闭浏览器,刷新浏览器后进行不丢失,仍然能够继续上传
文件夹上传
支持上传文件夹并保留层级结构,同样支持进度信息离线保存,刷新页面,关闭页面,重启系统不丢失上传进度。
下载示例
点击下载完整示例