news 2026/4/17 21:53:27

芯片制造SpringBoot如何实现大文件上传?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
芯片制造SpringBoot如何实现大文件上传?

开发者日记:2023年11月25日 周六 阴
项目名称:跨平台大文件传输系统(WebUploader+Vue3+SpringBoot+腾讯云COS)


项目背景与核心挑战

作为河南独立开发者,近期承接了一个高复杂度外包项目,客户要求实现20G级文件/文件夹跨浏览器上传下载,技术栈涉及:

  • 前端:Vue3(TypeScript)+ WebUploader(兼容IE8)
  • 后端:SpringBoot 3.0 + Oracle 21c
  • 存储:腾讯云COS(需处理分片上传与合并)
  • 兼容性:从IE8到现代浏览器(Chrome/Firefox/Safari/Edge/Opera)

现存痛点

  1. 网上开源方案仅支持单文件上传,无完整文件夹层级解析逻辑
  2. IE8的ActiveX控件在Windows 11上频繁崩溃
  3. Oracle数据库与MySQL的序列化差异导致进度存储失败
  4. 20G文件传输时,SpringBoot默认超时时间(1分钟)严重不足

技术方案设计

前端架构(Vue3 + WebUploader)

Chrome/Firefox

IE8

用户选择文件/文件夹

浏览器类型

使用FileSystemDirectoryHandle API

调用ActiveX控件递归读取

生成文件树结构(JSON)

计算文件ETag(替代MD5,兼容IE8)

分片上传(WebUploader)

本地存储进度(IndexedDB+localStorage)

后端架构(SpringBoot + Oracle)

接收分片

是否首片

创建Oracle任务记录(序列+BLOB)

更新分片进度(JDBC批处理)

存储分片到临时目录

是否全部分片完成

合并文件并上传COS

返回继续上传指令

关键数据库设计(Oracle)
-- 上传任务表CREATETABLEUPLOAD_TASK(TASK_ID VARCHAR2(36)PRIMARYKEY,FILE_ETAG VARCHAR2(64)NOTNULL,RELATIVE_PATH VARCHAR2(1024),-- 保留文件夹层级(如 /project/src/)TOTAL_CHUNKS NUMBER,UPLOADED_CHUNKS NUMBERDEFAULT0,STATUSVARCHAR2(20)CHECK(STATUSIN('PENDING','UPLOADING','COMPLETED','FAILED')),COS_KEY VARCHAR2(1024),CREATE_TIMETIMESTAMPDEFAULTSYSTIMESTAMP);-- 分片存储表(Oracle BLOB优化)CREATETABLEUPLOAD_CHUNK(CHUNK_ID VARCHAR2(72)PRIMARYKEY,-- TASK_ID+CHUNK_INDEXTASK_ID VARCHAR2(36)REFERENCESUPLOAD_TASK(TASK_ID),CHUNK_INDEX NUMBER,CHUNK_DATABLOB,CONSTRAINTUK_TASK_CHUNKUNIQUE(TASK_ID,CHUNK_INDEX));

核心代码实现

前端:文件夹上传与断点续传(Vue3 + TypeScript)
// src/components/FolderUploader.vueimport{ref,onMounted}from'vue';importWebUploaderfrom'webuploader';import{calculateFileETag}from'@/utils/fileHash';// 自定义ETag计算(兼容IE8)exportdefault{setup(){consttaskList=ref>([]);constuploader=ref(null);// 初始化上传器(兼容IE8)constinitUploader=()=>{constisIE8=document.documentMode===8;uploader.value=WebUploader.create({swf:'/static/Uploader.swf',// IE8回退server:'/api/upload/chunk',chunked:true,chunkSize:isIE8?4*1024*1024:20*1024*1024,// IE8限制4MB分片threads:isIE8?1:5,formData:{taskId:localStorage.getItem('currentTaskId')||''},timeout:0// 禁用超时(由后端控制)});// 恢复未完成任务(从IndexedDB)restoreTasksFromDB();};// 递归解析文件夹(跨浏览器)consthandleFolderSelect=async(e:Event)=>{constinput=e.targetasHTMLInputElement;constfiles=input.files;if(!files?.length)return;constparseFolder=async(entries:FileSystemEntry[],parentPath='')=>{for(letentryofentries){if(entry.isFile){constfile=(entryasFileSystemFileEntry).file!;constrelativePath=parentPath?`${parentPath}/${entry.name}`:entry.name;awaitaddUploadTask(file,relativePath);}elseif(entry.isDirectory){constdirReader=(entryasFileSystemDirectoryEntry).createReader();constnewEntries=awaitnewPromise(resolve=>{dirReader.readEntries(resolve);});awaitparseFolder(newEntries,parentPath?`${parentPath}/${entry.name}`:entry.name);}}};// Chrome/Firefox使用showDirectoryPickerif(files[0].webkitGetAsEntry){constentry=files[0].webkitGetAsEntry();if(entry?.isDirectory){constdirReader=entry.createReader();constentries=awaitnewPromise(resolve=>{dirReader.readEntries(resolve);});awaitparseFolder(entries);}else{awaitaddUploadTask(files[0],files[0].name);}}// IE8使用ActiveX(需用户授权)elseif(window.ActiveXObject){// ActiveX实现代码省略(需处理权限弹窗)}};// 添加上传任务constaddUploadTask=async(file:File,relativePath:string)=>{constetag=awaitcalculateFileETag(file);// 使用CRC32+文件大小替代MD5consttask={file,relativePath,etag,chunkCount:Math.ceil(file.size/uploader.value!.options.chunkSize),uploadedChunks:0};// 检查本地是否有未完成记录constexistingTask=awaitgetTaskFromDB(etag);if(existingTask){task.uploadedChunks=existingTask.uploadedChunks;}taskList.value.push(task);saveTaskToDB(task);startUpload(task);};onMounted(()=>{initUploader();document.getElementById('folderInput')?.addEventListener('change',handleFolderSelect);});return{taskList,uploader};}};
后端:SpringBoot分片处理与COS上传
// src/main/java/com/example/uploader/controller/UploadController.java@RestController@RequestMapping("/api/upload")publicclassUploadController{@AutowiredprivateUploadTaskRepositorytaskRepository;@AutowiredprivateUploadChunkRepositorychunkRepository;@AutowiredprivateCOSClientcosClient;// 腾讯云COS客户端// 分片上传接口@PostMapping("/chunk")publicResponseEntityhandleChunk(@RequestParam("file")MultipartFilefile,@RequestParam("taskId")StringtaskId,@RequestParam("chunkIndex")intchunkIndex,@RequestParam("totalChunks")inttotalChunks,@RequestParam("etag")Stringetag,@RequestParam("relativePath")StringrelativePath){// 1. 查询或创建任务UploadTasktask=taskRepository.findById(taskId).orElseGet(()->{UploadTasknewTask=newUploadTask();newTask.setTaskId(taskId);newTask.setFileEtag(etag);newTask.setRelativePath(relativePath);newTask.setTotalChunks(totalChunks);newTask.setStatus("UPLOADING");returntaskRepository.save(newTask);});// 2. 保存分片到Oracle BLOBUploadChunkchunk=newUploadChunk();chunk.setChunkId(taskId+"_"+chunkIndex);chunk.setTaskId(taskId);chunk.setChunkIndex(chunkIndex);try{chunk.setChunkData(file.getBytes());chunkRepository.save(chunk);}catch(IOExceptione){returnResponseEntity.status(500).body("分片保存失败");}// 3. 更新任务进度task.setUploadedChunks(chunkIndex+1);taskRepository.save(task);// 4. 检查是否全部上传完成if(task.getUploadedChunks()>=task.getTotalChunks()){// 启动异步合并任务mergeAndUploadToCOS(task);returnResponseEntity.ok("{\"status\":\"COMPLETED\"}");}returnResponseEntity.ok("{\"status\":\"SUCCESS\"}");}// 异步合并并上传COS@AsyncpublicvoidmergeAndUploadToCOS(UploadTasktask){try{// 1. 从Oracle读取所有分片Listchunks=chunkRepository.findByTaskIdOrderByChunkIndex(task.getTaskId());// 2. 合并文件(流式处理避免内存溢出)PathtempFile=Files.createTempFile("upload_",".tmp");try(OutputStreamout=Files.newOutputStream(tempFile)){for(UploadChunkchunk:chunks){out.write(chunk.getChunkData());}}// 3. 上传到腾讯云COSStringcosKey="uploads/"+task.getTaskId()+"/"+task.getRelativePath();cosClient.putObject(newPutObjectRequest("your-bucket",cosKey,tempFile.toFile()));// 4. 更新任务状态task.setStatus("COMPLETED");task.setCosKey(cosKey);taskRepository.save(task);// 5. 清理临时文件和分片Files.deleteIfExists(tempFile);chunkRepository.deleteByTaskId(task.getTaskId());}catch(Exceptione){task.setStatus("FAILED");taskRepository.save(task);}}}

关键问题解决

  1. IE8兼容性

    • 使用标签替代已废弃的加载Uploader.swf
    • 通过document.execCommand('SaveAs')实现IE8的下载功能
  2. Oracle性能优化

    • UPLOAD_CHUNK表的TASK_ID字段建立索引
    • 使用JDBC批处理更新进度(addBatch()+executeBatch()
  3. 大文件传输超时

    • 在SpringBoot配置中增加:
      server:tomcat:connection-timeout:0# 禁用连接超时spring:servlet:multipart:max-file-size:20GBmax-request-size:20GB
  4. 文件夹层级保留

    • 前端传递relativePath参数(如/docs/2023/report.pdf
    • 后端直接存储该路径,上传COS时保持原样

求助与社区支持

目前遇到以下难题,已在QQ群(374992201)发布详细日志:

  1. IE8的ActiveX控件在Windows 11上频繁弹出权限警告
  2. Oracle BLOB存储20G文件时出现ORA-01653表空间不足错误
  3. SpringBoot异步任务在合并大文件时被K8s容器终止

完整代码仓库

  • 前端:https://gitee.com/yourname/vue3-folder-uploader
  • 后端:https://gitee.com/yourname/springboot-cos-uploader

明日计划

  1. 实现WebUploader的IE8进度条显示
  2. 编写Oracle分片表的分区策略(按任务ID哈希分区)
  3. 测试20G文件在低带宽(2Mbps)下的传输稳定性

(日记结束)

附:技术栈对比表

模块原方案当前方案优化点
前端框架jQueryVue3 + TypeScript类型安全+组件化
上传组件WebUploader基础版定制版(支持文件夹+ETag)递归解析文件夹结构
后端语言JSPSpringBoot 3.0响应式编程+Oracle优化
数据库MySQLOracle 21cBLOB存储优化+分区表
对象存储百度OBS腾讯云COS适配不同的分片API规范

如需完整项目或调试协助,请联系QQ群或留言获取测试账号!

SQL示例

创建数据库

配置数据库连接

自动下载maven依赖

启动项目

启动成功

访问及测试

默认页面接口定义

在浏览器中访问

数据表中的数据

效果预览

文件上传

文件刷新续传

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

文件夹上传

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

批量下载

支持文件批量下载

下载续传

文件下载支持离线保存进度信息,刷新页面,关闭页面,重启系统均不会丢失进度信息。

文件夹下载

支持下载文件夹,并保留层级结构,不打包,不占用服务器资源。

示例下载

下载完整示例

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

风险操作系统:当保险消失在生活里,它才真正无处不在

《存量突围与算法重构:解构中国智慧保险的“实战逻辑”》专栏 第五篇(收官) 终局展望 01. 那个“消失”的账单,和那笔“没感觉”的服务 咱们先从一个你我每天都在经历,但可能早就习以为常的场景聊起。 问你个事儿:你现在还清楚记得,你上个月的手机话费是哪天扣的吗?…

作者头像 李华
网站建设 2026/4/18 11:05:09

C#每日面试题-Task和Thread的区别

C#每日面试题-Task和Thread的区别 在C#并发编程中,Task和Thread是两个高频出现的概念,也是面试中的核心考点。很多初学者容易将二者混淆,认为“Task就是封装后的Thread”,但实际上二者在设计理念、底层实现、使用场景上都存在本质…

作者头像 李华
网站建设 2026/4/18 8:40:58

【收藏必备】PyTorch手把手教你训练Transformer模型,从零开始实现大模型

本文详细介绍了如何使用PyTorch框架训练Transformer模型,从Tokenization、Embedding、位置编码到前向传播、损失计算和反向传播的全流程。文章通过model.py和train.py两个文件实现模型架构和训练过程,解释了残差连接等关键概念,强调现有框架使…

作者头像 李华
网站建设 2026/4/18 5:39:20

3大供应商协调管理技巧,助你搞定多方协作沟通与监督!

3大供应商协调管理技巧,助你搞定多方协作沟通与监督! 在会议服务行业,涉及众多供应商的多方协作是常见且关键的环节。有效的供应商协调管理能够确保会议顺利进行,提升服务质量。北京天德腾润公关策划有限公司作为专业会务服务机构…

作者头像 李华
网站建设 2026/4/18 13:35:27

基于springboot的个人博客网站标签 vue可视化统计

目录 技术栈选择后端实现前端可视化数据交互优化扩展功能 开发技术源码文档获取/同行可拿货,招校园代理 :文章底部获取博主联系方式! 技术栈选择 Spring Boot 作为后端框架,提供 RESTful API 接口;Vue.js 作为前端框架&#xff0…

作者头像 李华
网站建设 2026/4/18 6:30:04

基于springboot的房屋销售房产交易系统vue

目录 系统概述技术架构核心功能模块扩展性设计部署方案 开发技术源码文档获取/同行可拿货,招校园代理 :文章底部获取博主联系方式! 系统概述 基于SpringBoot和Vue的房屋销售房产交易系统是一个前后端分离的现代化平台,旨在提供高效的房产信息…

作者头像 李华