news 2025/12/25 20:15:37

JavaScript如何实现Web文件分片上传与断点续传?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaScript如何实现Web文件分片上传与断点续传?

Java老哥外包救星:原生JS大文件上传全栈方案(IE9兼容+20G断点续传)

兄弟,作为甘肃接外包的Java程序员,我太懂你现在的处境了——客户要20G大文件上传,还要文件夹层级保留、IE9兼容、加密传输,预算还卡得死死的。网上找的代码全是“文件上传半成品”,文件夹功能要么丢层级,要么IE9直接崩。别慌!我熬了半个月啃下的原生JS+SpringBoot全栈方案,今天全盘托出,保证你能直接给客户演示,验收时被夸“这钱花得值”!


一、方案核心(专治外包项目的“奇葩需求”)

1. 功能全覆盖(客户看了直点头)

  • 20G级大文件传输:分片上传(10MB/片),断点续传(localStorage+MySQL双存储进度,关浏览器/重启电脑不丢)。
  • 文件夹层级保留:递归遍历文件树(前端生成相对路径),后端按/父文件夹/子文件路径存储(IE9用“伪路径+元数据”方案兜底)。
  • 加密传输+存储:传输层HTTPS+AES-256(密钥动态生成),存储层SM4(国密算法,符合客户保密要求)。
  • 非打包下载:流式传输逐个文件(几万文件也不卡),支持“文件夹结构树”展示(避免服务器内存爆炸)。
  • 全浏览器兼容:IE9(XHR2+File API补丁)→ Edge/Chrome/Firefox → macOS/Linux/CentOS(信创环境)。

2. 预算友好(0商业授权费)

  • 原生JS实现:0商业库,用crypto-js(AES)+spark-md5(文件哈希),代码直接嵌入Vue3项目。
  • 轻量级依赖:仅需Vue3、axios、crypto-js,无额外费用。
  • 本地存储适配:文件直接存服务器(Tomcat部署路径可配置),无需OSS,代码动态适配Windows/Linux。

3. 客户要的“铁证”全给齐

  • 完整源码包(前端+后端+SQL脚本),导入就能跑。
  • 部署文档(Tomcat配置+MySQL连接+文件路径设置),手把手教客户运维。
  • 7*24小时支持:群里200+Java/前端大佬互助(QQ群:374992201),遇到坑直接甩日志截图,老炮儿带你改。

二、前端核心代码(Vue3兼容版,附详细注释)

1. 文件夹上传组件(兼容IE9+所有主流浏览器)

// 兼容IE9的polyfill(必须引入!) import 'es6-promise/auto'; // 补Promise import 'whatwg-fetch'; // 补fetch import Blob from 'blob-polyfill'; // 补Blob(IE9不支持slice) if (!window.console) window.console = { log: () => {}, error: () => {} }; // 补console // 依赖库(需手动安装:npm install crypto-js axios spark-md5) import CryptoJS from 'crypto-js'; import axios from 'axios'; import SparkMD5 from 'spark-md5'; export default { data() { return { uploadTasks: [], // 上传任务列表(核心数据) chunkSize: 10 * 1024 * 1024, // 10MB分片(20G文件分2000片,平衡速度与内存) aesKey: '', // AES密钥(从后端动态获取) currentTaskId: '', // 当前上传任务的ID isUploading: false // 全局上传状态锁 }; }, mounted() { this.initAesKey(); // 初始化AES密钥(首次加载时生成) this.checkResumeTasks(); // 启动时检查本地是否有未完成的任务 }, methods: { /** * 检查本地是否有未完成的上传任务(启动时自动执行) */ checkResumeTasks() { // 遍历localStorage所有key(实际项目中需优化,这里简化) for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); if (key.startsWith('upload_')) { const taskData = JSON.parse(localStorage.getItem(key)); this.uploadTasks.push(taskData); } } if (this.uploadTasks.length > 0) { this.$message.warning('检测到未完成的上传任务,是否继续?'); } } } };

三、后端核心代码(SpringBoot,附关键逻辑)

1. 分片上传接口(ChunkController.java)

// src/main/java/com/example/uploader/controller/ChunkController.java@RestController@RequestMapping("/api/upload")publicclassChunkController{@Value("${upload.chunk.size}")privatelongchunkSize;@AutowiredprivateUploadServiceuploadService;/** * 分片上传接口 */@PostMapping("/chunk")publicResponseEntityuploadChunk(@RequestParam("taskId")StringtaskId,@RequestParam("chunkIndex")intchunkIndex,@RequestParam("totalChunks")inttotalChunks,@RequestParam("filePath")StringfilePath,@RequestParam("chunk")MultipartFilechunk){try{// 1. 解密分片(AES-256)byte[]encryptedData=chunk.getBytes();StringaesKey=uploadService.getAesKeyFromKms();// 从KMS获取动态密钥byte[]decryptedData=uploadService.aesDecrypt(encryptedData,aesKey);// 2. 创建存储目录(兼容Linux/Windows)StringstoragePath=uploadService.getStoragePath()+filePath;Filedir=newFile(storagePath);if(!dir.exists()){dir.mkdirs();// 递归创建目录}// 3. 保存分片到服务器(非打包)StringchunkPath=storagePath+File.separator+chunkIndex;FilechunkFile=newFile(chunkPath);FileUtils.writeByteArrayToFile(chunkFile,decryptedData);// 使用Apache Commons IO// 4. 记录进度到MySQL(断点续传关键)UploadProgressprogress=newUploadProgress();progress.setTaskId(taskId);progress.setFilePath(filePath);progress.setChunkIndex(chunkIndex);progress.setTotalChunks(totalChunks);progress.setUploadedSize(decryptedData.length);progress.setStatus("UPLOADING");uploadService.saveOrUpdateProgress(progress);returnResponseEntity.ok().body(Result.success("分片上传成功"));}catch(Exceptione){e.printStackTrace();returnResponseEntity.status(500).body(Result.error("上传失败:"+e.getMessage()));}}}

2. 断点续传进度服务(UploadService.java)

// src/main/java/com/example/uploader/service/UploadService.java@ServicepublicclassUploadService{@AutowiredprivateUploadProgressMapperprogressMapper;@Value("${upload.storage.path}")privateStringstoragePath;@Value("${encryption.aes.key}")privateStringaesKey;/** * 保存或更新上传进度(支持MySQL) */publicvoidsaveOrUpdateProgress(UploadProgressprogress){UploadProgressexisting=progressMapper.selectByTaskIdAndFilePathAndChunkIndex(progress.getTaskId(),progress.getFilePath(),progress.getChunkIndex());if(existing!=null){progress.setId(existing.getId());progressMapper.updateById(progress);}else{progressMapper.insert(progress);}}}

3. 下载接口(DownloadController.java)

// src/main/java/com/example/uploader/controller/DownloadController.java@RestController@RequestMapping("/api/download")publicclassDownloadController{@AutowiredprivateUploadServiceuploadService;/** * 非打包下载文件夹(流式传输) */@GetMapping("/folder")publicvoiddownloadFolder(@RequestParam("taskId")StringtaskId,@RequestParam("filePath")StringfilePath,HttpServletResponseresponse)throwsIOException{// 1. 验证下载权限(根据业务ID校验)if(!uploadService.validateDownloadPermission(taskId)){response.sendError(403,"无下载权限");return;}// 2. 获取文件夹下所有文件列表(从数据库查询)ListfileList=uploadService.getFileListByPath(filePath);// 3. 设置响应头(非打包)response.setContentType("application/octet-stream");response.setHeader("Content-Disposition","attachment; filename=\""+filePath+"\"");// 4. 流式传输每个文件(避免内存溢出)for(FileInfofile:fileList){InputStreamfileStream=newFileInputStream(file.getPhysicalPath());IOUtils.copy(fileStream,response.getOutputStream());response.getOutputStream().flush();}response.getOutputStream().close();}}

四、数据库脚本(MySQL)

-- 创建上传进度表(记录分片上传状态)CREATETABLEIFNOTEXISTSupload_progress(idINTUNSIGNEDAUTO_INCREMENTPRIMARYKEY,task_idVARCHAR(255)NOTNULLCOMMENT'任务ID(如upload_1620000000_abc123)',file_pathVARCHAR(1000)NOTNULLCOMMENT'文件存储路径(如/upload_1620000000/folder_123/file.txt)',chunk_indexINTUNSIGNEDNOTNULLCOMMENT'当前分片索引(0开始)',total_chunksINTUNSIGNEDNOTNULLCOMMENT'总分片数',uploaded_sizeBIGINTUNSIGNEDNOTNULLCOMMENT'已上传大小(字节)',statusVARCHAR(50)NOTNULLDEFAULT'PENDING'COMMENT'状态:PENDING/RESUMING/UPLOADING/FAILED/SUCCESS',create_timeTIMESTAMPDEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间',update_timeTIMESTAMPDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT'更新时间')ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;-- 唯一约束(防止同一任务同一分片重复记录)CREATEUNIQUEINDEXUQ_Task_File_ChunkONupload_progress(task_id,file_path,chunk_index);

五、部署与兼容性调试(客户最关心的)

1. IE9兼容性(客户老机器必过)

  • File API补丁:引入Blob.js(https://github.com/eligrey/Blob.js),解决File.slice不支持问题(代码中已预留位置,需在index.html中引入)。
  • FormData兼容:IE9不支持FormData,代码中已用iframe模拟上传(无需额外处理,前端自动降级)。
  • localStorage容量:IE9的localStorage容量限制为5MB,大文件进度需分块存储(代码中已用taskId分key存储)。

2. 大文件分片(20G传输关键)

  • 分片大小:选10MB是因为IE9内存限制,太大可能导致浏览器崩溃;太小会增加请求次数(实际可根据客户网络调整)。
  • 断点续传:前端用localStorage缓存已上传的分片索引和大小,后端用MySQL记录,双重保障(客户重启电脑也能续传)。

3. 文件夹层级保留(客户核心需求)

  • 路径生成:现代浏览器用file.webkitRelativePath获取相对路径;IE9用随机生成的文件夹名兜底(需用户手动输入文件夹名,这里简化为随机字符串)。
  • 后端存储:后端按filePath字段创建目录结构(如E:/uploads/upload_1620000000/folder_123/file.txt),确保层级不变。

六、预算与合作模式(客户最关心的)

1. 预算控制(100元以内)

  • 源码一次性交付:提供完整前端Vue3组件、后端SpringBoot代码、数据库脚本,无后续授权费。
  • 免费技术支持:7*24小时远程协助(故障排查、版本升级、兼容性调试)。

2. 合作材料(满足客户采购要求)

  • 项目证明:提供过往外包项目合同(含项目名称、金额、验收报告)。
  • 技术资质:Java开发工具授权(IntelliJ IDEA)、服务器配置文档(Tomcat+MySQL)。

兄弟,这套方案你拿给客户演示,保证验收时客户拍大腿说“这钱花得值”!有问题直接甩日志到群里(QQ群:374992201),老炮儿我24小时在线帮你改。记住:不会就查文档,卡壳就问群友——咱Java程序员,接外包就是要“稳准狠”!

导入项目

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

工程

NOSQL

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

创建数据表

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

修改数据库连接信息

访问页面进行测试

文件存储路径

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

效果预览

文件上传

文件刷新续传

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

文件夹上传

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

下载示例

点击下载完整示例

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

HTTP协议在JavaScript大文件上传中如何处理重试逻辑?

我&#xff0c;一个被大文件上传逼疯的大三狗&#xff0c;想和你唠唠毕业设计的血泪史 最近为了做毕业设计&#xff0c;我把头发薅掉了小半——老师要的是“能打”的文件管理系统&#xff0c;核心需求就一条&#xff1a;10G大文件上传&#xff0c;还要支持文件夹、断点续传、加…

作者头像 李华
网站建设 2025/12/12 19:24:35

连接器防水设计

连接器广泛应用于各种用电的场合&#xff0c;而连接器往往位于系统,子系统或部件/组件的界面位置&#xff0c;故防水有时成为连接器必不可少的要求。要实现可靠地防水&#xff0c;设计时需系统地考虑相关因素&#xff1a;防护的等级要求密封材料的选择合适的尺寸结构-导向&…

作者头像 李华
网站建设 2025/12/12 19:24:29

灵感不再流失!华硕ProArt 创16,把你的创作工作室随身携带

对于专业创作者而言&#xff0c;灵感往往不期而至。它可能出现在通勤的地铁上&#xff0c;喧闹的咖啡馆里&#xff0c;或是拍摄现场。然而&#xff0c;传统的移动办公设备往往难以承载8K剪辑、3D渲染或大模型部署等重度任务。华硕ProArt 创16的出现&#xff0c;打破这一桎梏。它…

作者头像 李华
网站建设 2025/12/12 19:24:20

终极全模态AI革命:Qwen2.5-Omni-3B如何用30亿参数重塑行业标准

2025年&#xff0c;人工智能领域迎来历史性突破——Qwen2.5-Omni-3B全模态大模型正式开源发布。这款仅搭载30亿参数的轻量化模型&#xff0c;凭借其创新的端到端多模态处理架构&#xff0c;在文本、图像、音频、视频四模态融合任务中展现出卓越性能&#xff0c;为全模态AI技术的…

作者头像 李华
网站建设 2025/12/12 19:23:45

6个完整字重:PingFangSC字体包实现跨平台完美显示

6个完整字重&#xff1a;PingFangSC字体包实现跨平台完美显示 【免费下载链接】PingFangSC PingFangSC字体包文件、苹果平方字体文件&#xff0c;包含ttf和woff2格式 项目地址: https://gitcode.com/gh_mirrors/pi/PingFangSC 还在为网站在不同设备上字体显示不一致而烦…

作者头像 李华