2026/2/16 22:54:35
网站建设
项目流程
沈阳高端做网站建设,临沂网站公司,网站设计与网页制作团队,制作游戏的软件手机版咱福州软件工程狗实锤了#xff01;最近为了毕设焦头烂额——要做个能打的大文件管理系统#xff0c;还要支持10G上传、断点续传、加密啥的#xff0c;关键是得兼容IE8这种“古董”浏览器#xff08;学校机房那台Win7IE9的老机器#xff0c;点个按钮都像在蹦迪#xff09…咱福州软件工程狗实锤了最近为了毕设焦头烂额——要做个能打的大文件管理系统还要支持10G上传、断点续传、加密啥的关键是得兼容IE8这种“古董”浏览器学校机房那台Win7IE9的老机器点个按钮都像在蹦迪。找了一圈开源代码不是缺胳膊少腿就是“仅示例”出了问题连个搭话的人都没有……今天必须把压箱底的方案掏出来顺便求大神救救孩子需求拆解我要的到底是个啥简单说就仨核心大文件上传10G起步断点续传关浏览器/重启电脑都不怕支持文件夹保留层级比如/部门/2024报告/数据.xlsx。加密传输过程HTTPS存储到OSS前AES加密密钥自己管阿里云也偷不走。兼容IE8包括龙芯、红莲花这些信创浏览器、Win7IE9学校老机器也得跑起来。前端Vue3 原生JS WebUploader兼容IE8的救命稻草IE8不支持H5的File API只能靠Flash补全。WebUploader是百度开源的支持Flash/H5双模式正好适配老浏览器。前端核心逻辑分片上传、断点查询、文件夹遍历、加密预处理。1. 前端关键代码Vue3组件import SparkMD5 from spark-md5; // 用于生成文件唯一标识MD5 import WebUploader from webuploader; // 引入WebUploader export default { data() { return { uploader: null, progress: 0, fileMd5: , // 当前文件的MD5用于断点续传 chunkSize: 2 * 1024 * 1024, // 分片大小2MB10G文件分5000片 uploadedChunks: [] // 已上传的分片序号 }; }, mounted() { this.initUploader(); }, methods: { initUploader() { // 初始化WebUploader兼容IE8的Flash模式 this.uploader WebUploader.create({ swf: /static/webuploader/Uploader.swf, // Flash路径IE8必须 server: /api/upload/init, // 初始化接口获取文件MD5 pick: #filePicker, dnd: #dndArea, paste: document.body, chunked: true, // 开启分片 chunkSize: this.chunkSize, compress: false, // 不压缩大文件必须 fileNumLimit: 1000, // 最大文件数 fileSizeLimit: 10 * 1024 * 1024 * 1024, // 10G限制 accept: { title: All Files, extensions: * } }); // 文件加入队列时生成MD5用于断点续传 this.uploader.on(fileQueued, (file) { this.fileMd5 ; // 重置MD5 this.uploadedChunks []; // 重置已上传分片 this.calculateFileMd5(file); // 计算文件MD5 }); // 分片上传前查询已上传的分片 this.uploader.on(uploadBeforeSend, (obj, data) { data.md5 this.fileMd5; // 传递MD5给服务端 data.chunk obj.chunk; // 当前分片序号 data.chunks obj.chunks; // 总分片数 }); // 上传进度更新 this.uploader.on(uploadProgress, (file, percentage) { this.progress Math.round(percentage * 100); }); // 上传完成回调 this.uploader.on(uploadFinished, (file) { this.$message.success(上传完成); }); }, // 计算文件MD5关键断点续传的唯一标识 calculateFileMd5(file) { const blobSlice File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice; const chunkSize this.chunkSize; const chunks Math.ceil(file.size / chunkSize); let currentChunk 0; const spark new SparkMD5.ArrayBuffer(); const fileReader new FileReader(); fileReader.onload (e) { spark.append(e.target.result); // 读取分片内容并计算MD5 currentChunk; if (currentChunk chunks) { loadNext(); } else { this.fileMd5 spark.end(); // 所有分片读取完成得到最终MD5 // 查询服务端已上传的分片 this.queryUploadedChunks(this.fileMd5); } }; const loadNext () { const start currentChunk * chunkSize; const end Math.min(start chunkSize, file.size); fileReader.readAsArrayBuffer(blobSlice.call(file, start, end)); }; loadNext(); }, // 查询服务端已上传的分片断点续传核心 async queryUploadedChunks(md5) { try { const res await this.$http.get(/api/upload/chunks?md5${md5}); this.uploadedChunks res.data.uploadedChunks; // 服务端返回已上传的分片序号如[0,1,2] // 告诉WebUploader跳过已上传的分片 this.uploader.options.chunkRetry 0; // 失败不重试已上传的分片跳过 this.uploader.upload(); // 开始上传 } catch (err) { console.error(查询已上传分片失败, err); } }, startUpload() { this.uploader.upload(); }, pauseUpload() { this.uploader.stop(); } } };2. 前端兼容性处理IE8依赖FlashUploader.swf需在index.html中引入flash.js解决跨域问题。文件夹上传IE9支持webkitdirectory属性WebUploader自动处理IE8只能逐个上传文件需手动记录路径比如让用户输入文件夹结构或者在上传时让用户在文件名前加路径前缀如部门/2024报告/文件.txt。加密预处理敏感文件可在前端用CryptoJS.AES.encrypt加密后再上传密钥由用户输入后端存储时二次加密。后端SpringBoot 分片合并 加密存储后端核心逻辑接收分片、记录进度、合并文件、加密存储到OSS。1. 数据库设计MySQL需要两张表file_info文件元信息和file_chunk分片记录。-- 文件元信息表CREATETABLEfile_info(idBIGINTPRIMARYKEYAUTO_INCREMENT,file_nameVARCHAR(255)NOTNULL,-- 文件名含路径如部门/2024报告/数据.xlsxfile_sizeBIGINTNOTNULL,-- 文件大小字节md5VARCHAR(32)NOTNULL,-- 文件MD5唯一标识oss_pathVARCHAR(255),-- OSS存储路径加密后的文件encrypt_keyVARCHAR(255),-- 加密密钥AES密钥Base64编码create_timeDATETIMEDEFAULTCURRENT_TIMESTAMP);-- 文件分片记录表CREATETABLEfile_chunk(idBIGINTPRIMARYKEYAUTO_INCREMENT,file_md5VARCHAR(32)NOTNULL,-- 关联file_info.md5chunk_numberINTNOTNULL,-- 分片序号0开始chunk_pathVARCHAR(255)NOTNULL,-- 分片临时存储路径is_uploadedTINYINTDEFAULT0,-- 是否已上传0未上传1已上传create_timeDATETIMEDEFAULTCURRENT_TIMESTAMP,UNIQUEKEY(file_md5,chunk_number)-- 防止重复分片);2. 后端关键接口SpringBootRestControllerRequestMapping(/api/upload)publicclassUploadController{AutowiredprivateFileServicefileService;// 初始化上传生成文件MD5并查询已上传分片PostMapping(/init)publicResultinitUpload(RequestParam(md5)Stringmd5){FileRecordfileRecordfileService.getByMd5(md5);if(fileRecord!null){// 文件已存在秒传returnResult.success(文件已存在,fileRecord.getOssPath());}// 创建分片记录表初始化所有分片为未上传fileService.initChunks(md5);returnResult.success();}// 查询已上传的分片GetMapping(/chunks)publicResultqueryUploadedChunks(RequestParam(md5)Stringmd5){ListuploadedChunksfileService.getUploadedChunks(md5);returnResult.success(查询成功,Map.of(uploadedChunks,uploadedChunks));}// 接收分片上传PostMapping(/chunk)publicResultuploadChunk(RequestParam(file)MultipartFilefile,RequestParam(md5)Stringmd5,RequestParam(chunk)IntegerchunkNumber,RequestParam(chunks)IntegertotalChunks)throwsIOException{// 保存分片到临时目录本地或OSS临时空间StringtempDir/tmp/upload/md5;FiledirnewFile(tempDir);if(!dir.exists())dir.mkdirs();StringchunkPathtempDir/chunk_chunkNumber;file.transferTo(newFile(chunkPath));// 记录分片已上传fileService.markChunkUploaded(md5,chunkNumber);// 检查是否所有分片已上传触发合并if(fileService.isAllChunksUploaded(md5,totalChunks)){fileService.mergeChunks(md5,totalChunks);}returnResult.success();}// 合并分片并加密存储到OSSpublicvoidmergeChunks(Stringmd5,IntegertotalChunks)throwsIOException{FileRecordfileRecordfileService.getByMd5(md5);if(fileRecordnull)thrownewRuntimeException(文件不存在);// 合并分片按顺序读取临时文件写入最终文件StringtempDir/tmp/upload/md5;FileoutputFilenewFile(tempDir/merged_System.currentTimeMillis());try(RandomAccessFilerafnewRandomAccessFile(outputFile,rw)){for(inti0;itotalChunks;i){FilechunkFilenewFile(tempDir/chunk_i);byte[]bytesFiles.readAllBytes(chunkFile.toPath());raf.write(bytes);chunkFile.delete();// 删除临时分片}}// 加密文件AES加密StringencryptKeyAESUtil.generateKey();// 生成随机密钥或用户传入byte[]encryptedBytesAESUtil.encrypt(Files.readAllBytes(outputFile.toPath()),encryptKey);// 上传加密后的文件到OSS阿里云OSS SDKStringossPathencrypted_files/fileRecord.getFileName();OSSClientossClientnewOSSClient(oss-cn-hangzhou.aliyuncs.com,accessKeyId,accessKeySecret);ossClient.putObject(your-bucket,ossPath,newByteArrayInputStream(encryptedBytes));// 更新文件元信息删除临时目录fileRecord.setOssPath(ossPath);fileRecord.setEncryptKey(encryptKey);fileRecord.setFileSize(outputFile.length());fileRecordMapper.updateById(fileRecord);FileUtils.deleteDirectory(newFile(tempDir));}}3. 加密工具类AESpublicclassAESUtil{privatestaticfinalStringALGORITHMAES;privatestaticfinalStringKEY_ALGORITHMAES;privatestaticfinalStringDEFAULT_CIPHER_ALGORITHMAES/ECB/PKCS5Padding;// 生成随机密钥Base64编码publicstaticStringgenerateKey(){KeyGeneratorkeyGenKeyGenerator.getInstance(KEY_ALGORITHM);keyGen.init(256);// 256位密钥更安全SecretKeysecretKeykeyGen.generateKey();returnBase64.getEncoder().encodeToString(secretKey.getEncoded());}// 加密文件内容publicstaticbyte[]encrypt(byte[]data,Stringkey)throwsException{KeysecretKeynewSecretKeySpec(Base64.getDecoder().decode(key),KEY_ALGORITHM);CiphercipherCipher.getInstance(DEFAULT_CIPHER_ALGORITHM);cipher.init(Cipher.ENCRYPT_MODE,secretKey);returncipher.doFinal(data);}// 解密文件内容下载时用publicstaticbyte[]decrypt(byte[]data,Stringkey)throwsException{KeysecretKeynewSecretKeySpec(Base64.getDecoder().decode(key),KEY_ALGORITHM);CiphercipherCipher.getInstance(DEFAULT_CIPHER_ALGORITHM);cipher.init(Cipher.DECRYPT_MODE,secretKey);returncipher.doFinal(data);}}兼容性兜底方案IE8/IE9Flash上传WebUploader的Flash模式在IE8下必须需确保swf文件路径正确且浏览器允许Flash运行学校机房可能需要调整安全设置。分片大小IE8对分片支持一般建议分片大小设为2MB太小会增加请求次数太大容易超时。文件夹上传IE8不支持webkitdirectory只能让用户手动输入文件夹路径比如在文件名前加部门/2024报告/前缀后端根据路径创建OSS目录。毕设演示注意事项本地测试用Win7IE9虚拟机测试上传流程断点续传上传到50%时关闭浏览器重新打开继续上传。OSS演示展示加密后的文件在OSS中的存储密钥单独管理不展示给用户。兼容性截图拍IE8/龙芯浏览器的上传界面证明“真·全浏览器支持”。求救大神在哪里现在代码框架搭好了但有几个坑还没填IE8下Flash上传的跨域问题crossdomain.xml配置。大文件分片合并时的内存溢出10G文件合并时Java内存不够怎么办可能需要流式合并。加密密钥的安全存储用户忘记密钥怎么办需要设计密钥找回功能。群里加了个374992201新人有红包求大神来群里指导或者直接甩个DEMO链接毕设答辩就靠这个了要是能上线说不定还能接点外包群里说推荐项目提20%提成10万项目提2万比打工香多了PS老师说“能跑起来就行”但我想做得更完美——毕竟这是大学最后作业了冲就完事了SQL示例创建数据库配置数据库连接自动下载maven依赖启动项目启动成功访问及测试默认页面接口定义在浏览器中访问数据表中的数据效果预览文件上传文件刷新续传支持离线保存文件进度在关闭浏览器刷新浏览器后进行不丢失仍然能够继续上传文件夹上传支持上传文件夹并保留层级结构同样支持进度信息离线保存刷新页面关闭页面重启系统不丢失上传进度。示例下载下载完整示例