news 2026/2/17 20:40:59

前端如何通过FormData实现Java大文件分片上传的进度回传?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
前端如何通过FormData实现Java大文件分片上传的进度回传?

大文件传输系统解决方案

作为北京某软件公司的项目负责人,我针对大文件传输需求提出以下完整解决方案:

一、需求分析与技术选型

基于贵公司需求,我们决定采用自主研发+部分开源组件整合的方案,主要原因如下:

  1. 现有开源组件无法完全满足需求(如文件夹层级保留、IE8兼容性等)
  2. 业务场景特殊(央企国企客户对安全性、稳定性要求极高)
  3. 需要深度集成现有技术栈(JSP/Spring Boot/Vue等多框架支持)

核心技术选型

  • 传输协议:HTTP+分片上传(兼容性最好)
  • 断点续传:本地存储+服务端校验结合方案
  • 加密模块:支持SM4/AES可配置加密
  • 存储方案:阿里云OSS+本地存储双模式
  • 前端适配:基于WebSocket的进度通知机制

二、系统架构设计

后端架构

┌───────────────────────────────────┐ │ 应用层 │ │ ┌─────────┐ ┌─────────┐ │ │ │上传模块 │ │下载模块 │ │ │ └─────────┘ └─────────┘ │ │ │ ├──────────────────────────────────┤ │ 服务层 │ │ ┌─────────┐ ┌─────────┐ │ │ │分片管理 │ │加密服务 │ │ │ └─────────┘ └─────────┘ │ │ ┌─────────┐ ┌─────────┐ │ │ │断点续传 │ │存储适配 │ │ │ └─────────┘ └─────────┘ │ └──────────────────────────────────┘

前端架构

┌───────────────────────────────────┐ │ UI组件层 │ │ ┌───────────────────────┐ │ │ │ 文件选择器 │ │ │ └───────────────────────┘ │ │ ┌───────────────────────┐ │ │ │ 传输队列 │ │ │ └───────────────────────┘ │ │ ┌───────────────────────┐ │ │ │ 进度展示 │ │ │ └───────────────────────┘ │ ├───────────────────────────────────┤ │ 核心逻辑层 │ │ ┌─────────┐ ┌─────────┐ │ │ │分片处理 │ │加密处理 │ │ │ └─────────┘ └─────────┘ │ │ ┌─────────┐ ┌─────────┐ │ │ │断点恢复 │ │多框架适配│ │ │ └─────────┘ └─────────┘ │ └──────────────────────────────────┘

三、关键功能实现代码示例

后端核心代码(Java)

1. 文件分片上传接口
@RestController@RequestMapping("/api/upload")publicclassFileUploadController{@PostMapping("/init")publicResponseEntityinitUpload(@RequestParamStringfileId,@RequestParamStringfileName,@RequestParamlongfileSize,@RequestParamintchunkSize){// 初始化上传记录UploadRecordrecord=newUploadRecord();record.setFileId(fileId);record.setFileName(fileName);record.setFileSize(fileSize);record.setChunkSize(chunkSize);record.setStatus(UploadStatus.INIT);uploadService.saveRecord(record);returnResponseEntity.ok().build();}@PostMapping("/chunk")publicResponseEntityuploadChunk(@RequestParamStringfileId,@RequestParamintchunkNumber,@RequestParamMultipartFilechunk){// 处理分片上传uploadService.processChunk(fileId,chunkNumber,chunk);returnResponseEntity.ok().build();}@PostMapping("/complete")publicResponseEntitycompleteUpload(@RequestParamStringfileId,@RequestParamStringfileHash){// 验证并合并文件booleansuccess=uploadService.mergeChunks(fileId,fileHash);if(success){returnResponseEntity.ok().build();}else{returnResponseEntity.status(HttpStatus.CONFLICT).build();}}}
2. 断点续传服务
@ServicepublicclassUploadServiceImplimplementsUploadService{@OverridepublicvoidprocessChunk(StringfileId,intchunkNumber,MultipartFilechunk){// 1. 校验分片if(!validateChunk(fileId,chunkNumber,chunk)){thrownewBusinessException("分片校验失败");}// 2. 存储分片(加密存储)StringchunkKey=getChunkKey(fileId,chunkNumber);storageService.storeChunk(chunkKey,encryptChunk(chunk));// 3. 更新进度updateProgress(fileId,chunkNumber);}privatebooleanvalidateChunk(StringfileId,intchunkNumber,MultipartFilechunk){// 实现分片校验逻辑returntrue;}privatevoidupdateProgress(StringfileId,intchunkNumber){// 更新数据库中的上传进度UploadRecordrecord=uploadRepository.findByFileId(fileId);record.getCompletedChunks().add(chunkNumber);uploadRepository.save(record);// 同时更新Redis缓存redisTemplate.opsForSet().add("upload:progress:"+fileId,chunkNumber);}}

前端核心代码(Vue2示例)

1. 文件上传组件
exportdefault{data(){return{files:[],uploadQueue:[],progress:{},chunkSize:5*1024*1024// 5MB}},methods:{handleFileChange(e){constfiles=Array.from(e.target.files);this.prepareUpload(files);},prepareUpload(files){files.forEach(file=>{constfileId=this.generateFileId(file);this.uploadQueue.push({fileId,file,status:'pending',chunks:this.splitFile(file)});});},splitFile(file){constchunks=[];letstart=0;while(start<file.size){constend=Math.min(start+this.chunkSize,file.size);chunks.push({start,end,blob:file.slice(start,end)});start=end;}returnchunks;},asyncstartUpload(){for(constitemofthis.uploadQueue){awaitthis.uploadFile(item);}},asyncuploadFile(item){// 初始化上传awaitthis.$http.post('/api/upload/init',{fileId:item.fileId,fileName:item.file.name,fileSize:item.file.size,chunkSize:this.chunkSize});// 上传分片for(leti=0;i<item.chunks.length;i++){// 检查是否已上传过该分片constisUploaded=awaitthis.checkChunkUploaded(item.fileId,i);if(isUploaded)continue;constformData=newFormData();formData.append('fileId',item.fileId);formData.append('chunkNumber',i);formData.append('chunk',item.chunks[i].blob);awaitthis.$http.post('/api/upload/chunk',formData,{onUploadProgress:progress=>{this.updateProgress(item.fileId,i,progress);}});}// 完成上传awaitthis.$http.post('/api/upload/complete',{fileId:item.fileId,fileHash:awaitthis.calculateHash(item.file)});item.status='completed';},updateProgress(fileId,chunkIndex,progress){if(!this.progress[fileId]){this.progress[fileId]={};}this.progress[fileId][chunkIndex]=progress;}}}
2. IE8兼容方案
// ie8-compat.jsif(!Array.prototype.forEach){Array.prototype.forEach=function(callback,thisArg){varT,k;if(this==null){thrownewTypeError(' this is null or not defined');}varO=Object(this);varlen=O.length>>>0;if(typeofcallback!=="function"){thrownewTypeError(callback+' is not a function');}if(arguments.length>1){T=thisArg;}k=0;while(k<len){varkValue;if(kinO){kValue=O[k];callback.call(T,kValue,k,O);}k++;}};}// File API 兼容if(!window.FileReader){document.write('');}

四、技术难点解决方案

1. 文件夹层级保留方案

采用树形结构元数据存储:

{"folderId":"123","name":"project","type":"folder","children":[{"fileId":"456","name":"document.pdf","type":"file","size":102400,"chunks":[]},{"folderId":"789","name":"images","type":"folder","children":[]}]}

2. 大文件夹下载实现

publicvoiddownloadFolder(HttpServletResponseresponse,StringfolderId){// 1. 获取文件夹结构FolderStructurefolder=folderService.getFolderStructure(folderId);// 2. 设置响应头response.setContentType("application/octet-stream");response.setHeader("Content-Disposition","attachment; filename=\""+folder.getName()+".folder\"");// 3. 流式传输文件夹内容try(OutputStreamout=response.getOutputStream()){downloadFolderRecursive(out,folder);}}privatevoiddownloadFolderRecursive(OutputStreamout,FolderStructurefolder){// 写入文件夹标记writeFolderHeader(out,folder);// 处理子文件for(FileItemfile:folder.getFiles()){writeFileHeader(out,file);transferFileContent(out,file);}// 递归处理子文件夹for(FolderStructuresubFolder:folder.getSubFolders()){downloadFolderRecursive(out,subFolder);}// 写入文件夹结束标记writeFolderFooter(out,folder);}

3. 加密传输流程

客户端: 1. 生成随机对称密钥K 2. 使用K加密文件数据 3. 使用服务端公钥加密K 4. 传输加密后的数据和加密后的K 服务端: 1. 使用私钥解密得到K 2. 使用K解密文件数据 3. 使用配置的存储加密算法(如SM4)重新加密存储 解密下载时逆向此流程

五、商务合作方案

基于贵公司需求,我们提供以下授权方案:

  1. 买断授权:98万元一次性买断,包含:

    • 不限项目数的永久使用权
    • 源代码交付(可选)
    • 5年免费升级维护
    • 专属技术支持团队
  2. 资质文件:可提供全套央企合作资料:

    • 中国移动文件传输系统合同(2022年)
    • 国家电网安全传输平台软件著作权
    • 信创环境适配认证证书
    • 工商银行项目转账凭证
    • 企业全套资质文件
  3. 实施计划

    • 第1周:环境评估与方案确认
    • 第2-3周:系统集成与适配开发
    • 第4周:内部测试与安全审计
    • 第5周:上线部署与人员培训

六、技术保障措施

  1. 稳定性保障

    • 传输服务集群部署,单节点故障自动转移
    • 分片存储设计,避免大内存占用
    • 完善的日志监控系统(ELK+Prometheus)
  2. 兼容性测试矩阵

浏览器/OSWin7Win10macOSCentOS
IE8✔️ 已验证---
Chrome✔️✔️✔️✔️
Firefox✔️✔️✔️✔️
360安全浏览器✔️✔️--
  1. 性能指标
    • 单服务器支持100+并发上传
    • 断点信息持久化成功率>99.99%
    • 加密/解密吞吐量≥200MB/s

如需更详细的技术方案或演示,我可安排技术团队进行专项对接。

导入项目

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

工程

NOSQL

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

创建数据表

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

修改数据库连接信息

访问页面进行测试

文件存储路径

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

效果预览

文件上传

文件刷新续传

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

文件夹上传

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

下载示例

点击下载完整示例

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

【AutoGLM技术突围之路】:解码“沉思”背后的智能决策引擎

第一章&#xff1a;AutoGLM技术突围之路的背景与意义在人工智能快速演进的当下&#xff0c;大语言模型&#xff08;LLM&#xff09;正逐步成为推动智能应用落地的核心引擎。然而&#xff0c;传统模型在面对复杂任务时往往依赖人工干预与手动调参&#xff0c;难以实现端到端的自…

作者头像 李华
网站建设 2026/2/17 19:15:49

Prompt优化进入深水区,Open-AutoGLM高级改写技术全面解析

第一章&#xff1a;Prompt优化进入深水区的时代背景随着大语言模型&#xff08;LLM&#xff09;在自然语言处理领域的广泛应用&#xff0c;Prompt工程已从简单的指令拼接演变为系统化的交互设计科学。早期的Prompt多依赖经验性表达&#xff0c;而当前模型能力的跃迁迫使开发者深…

作者头像 李华
网站建设 2026/2/17 8:54:07

25.1 就业市场洞察:AIGC产品经理招聘现状与趋势

25.1 就业市场洞察:AIGC产品经理招聘现状与趋势 课程概述 从本章开始,我们将进入面试篇的学习。在前面的章节中,我们系统学习了AIGC技术和产品设计的各个方面。本章将重点关注AIGC产品经理的职业发展,帮助大家更好地了解就业市场、准备求职面试和规划职业发展。 本节课作…

作者头像 李华
网站建设 2026/2/3 2:17:56

Prompt效率提升300%,Open-AutoGLM改写秘籍首次公开

第一章&#xff1a;Prompt效率提升300%&#xff0c;Open-AutoGLM改写秘籍首次公开在大模型应用开发中&#xff0c;Prompt工程直接影响推理质量与响应速度。Open-AutoGLM作为开源自动Prompt优化框架&#xff0c;通过语义增强与结构重写机制&#xff0c;显著提升指令理解准确率。…

作者头像 李华
网站建设 2026/2/5 23:19:30

仿Open-AutoGLM浏览器插件开发实战(核心模块深度解析)

第一章&#xff1a;仿Open-AutoGLM浏览器插件开发概述随着大语言模型&#xff08;LLM&#xff09;在自动化任务中的广泛应用&#xff0c;浏览器插件作为连接用户操作与智能推理的桥梁&#xff0c;正变得愈发重要。仿Open-AutoGLM插件旨在复现类似AutoGLM的核心功能&#xff0c;…

作者头像 李华
网站建设 2026/2/4 13:16:41

25.5 谈薪选岗指南:哪些公司值得加入

25.5 谈薪选岗指南:哪些公司值得加入 1. 引言 1.1 为什么谈薪选岗如此重要? 在前面的章节中,我们学习了如何准备简历、如何应对面试。现在,当你成功通过面试,拿到Offer时,将面临一个新的挑战——如何谈薪?如何选岗? 很多求职者在拿到Offer后,往往因为不了解市场行…

作者头像 李华