军工领域,JAVA大文件分块上传的示例代码是什么?

我,一个被大文件上传逼疯的大三狗,想和你唠唠毕业设计的血泪史

最近为了做毕业设计,我把头发薅掉了小半——老师要的是“能打”的文件管理系统,核心需求就一条:10G大文件上传,还要支持文件夹、断点续传、加密传输,兼容IE8和国产浏览器。网上翻了三天三夜,找到的代码不是缺胳膊少腿(比如分片上传只写一半),就是兼容性差到连IE9都卡成PPT,更离谱的是作者留个QQ就消失,出了问题根本找不到人!

得,硬着头皮自己上吧。今天就把我踩过的坑、写好的代码掏出来,帮和我一样的学弟学妹少走弯路——毕竟毕业答辩时,老师可不管你用了啥“祖传代码”,能跑能演示才是王道!


一、需求拆解:大文件上传的“九九八十一难”

先理清楚核心需求,咱得一个个啃:

  1. 10G大文件上传:必须分片(比如每片5MB),支持断点续传(关浏览器、重启电脑都不丢进度);
  2. 文件夹上传:保留层级结构(比如“/文档/报告/2024.docx”),兼容IE8(不能用webkitdirectory这种现代API);
  3. 加密传输+存储:传输时用AES加密,服务器存加密后的文件,密钥单独管理;
  4. 兼容老古董:IE8/9、龙芯浏览器、红莲花这些信创浏览器,得用原生JS,别整花里胡哨的框架;
  5. 后端SpringBoot+Vue3:前端用Vue3 CLI,后端用SpringBoot,数据库MySQL,服务器Tomcat6.0(别问,学校实验室的老机器就这样)。

二、前端:原生JS实现分片上传+断点续传(Vue3版)

先从前端说起。大文件上传的核心是分片+断点续传,原理是把文件切成小块(比如5MB/片),每传完一片就告诉服务器“这片传好了”,最后再合并。断点续传的关键是记录已上传的分片,哪怕浏览器关了,下次打开还能接着传。

1. 分片上传逻辑(原生JS)

File.slice()切分文件,用XMLHttpRequest上传分片(兼容IE8)。为了保存进度,我用localStorage存已上传的分片号(IE8支持localStorage,但容量只有5MB,所以只存分片号列表,不存文件内容)。

关键代码(Vue3组件):

// 文件上传组件:FileUploader.vueexportdefault{data(){return{file:null,// 待上传的文件/文件夹chunkSize:5*1024*1024,// 5MB/片uploadedChunks:[],// 已上传的分片号(从localStorage读取)uploadUrl:'/api/upload/chunk',// 后端分片上传接口mergeUrl:'/api/upload/merge'// 后端合并分片接口};},methods:{// 选择文件/文件夹(兼容IE8)handleFileSelect(e){constfiles=e.target.files;if(files.length===0)return;this.file=files[0];this.startUpload();},// 开始上传(分片+断点续传)asyncstartUpload(){if(!this.file)return;consttotalChunks=Math.ceil(this.file.size/this.chunkSize);constfileId=this.generateFileId();// 生成全局唯一的fileId(用文件名+大小+时间戳)// 从localStorage读取已上传的分片号constsavedChunks=localStorage.getItem(fileId)?JSON.parse(localStorage.getItem(fileId)):[];this.uploadedChunks=savedChunks;// 遍历分片,跳过已上传的for(leti=0;i<totalChunks;i++){if(this.uploadedChunks.includes(i)){console.log(`分片${i}已上传,跳过`);continue;}conststart=i*this.chunkSize;constend=Math.min(start+this.chunkSize,this.file.size);constchunk=this.file.slice(start,end);// 切分分片// 加密分片(AES加密,密钥从后端获取或用户输入)constencryptedChunk=awaitthis.encryptChunk(chunk);// 上传分片(兼容IE8的XHR)constxhr=newXMLHttpRequest();xhr.open('POST',this.uploadUrl,true);xhr.setRequestHeader('Content-Type','application/octet-stream');xhr.setRequestHeader('fileId',fileId);xhr.setRequestHeader('chunkIndex',i);xhr.setRequestHeader('totalChunks',totalChunks);xhr.onload=()=>{if(xhr.status===200){this.uploadedChunks.push(i);localStorage.setItem(fileId,JSON.stringify(this.uploadedChunks));// 保存进度console.log(`分片${i}上传成功`);if(this.uploadedChunks.length===totalChunks){this.mergeChunks(fileId,totalChunks);// 所有分片上传完成,触发合并}}else{console.error(`分片${i}上传失败:${xhr.statusText}`);}};xhr.send(encryptedChunk);}},// 生成文件唯一ID(防重复)generateFileId(){return`${this.file.name}-${this.file.size}-${Date.now()}`;},// AES加密分片(密钥从后端获取)asyncencryptChunk(chunk){constkey=awaitthis.getKeyFromServer();// 假设从后端接口获取AES密钥constiv=crypto.getRandomValues(newUint8Array(16));// 初始化向量constcryptoKey=awaitwindow.crypto.subtle.importKey('raw',newTextEncoder().encode(key),{name:'AES-CBC'},false,['encrypt']);constencrypted=awaitwindow.crypto.subtle.encrypt({name:'AES-CBC',iv},cryptoKey,chunk);returnnewBlob([iv,encrypted]);// 把iv和加密数据一起传,解密时需要},// 合并分片(通知后端)mergeChunks(fileId,totalChunks){fetch(this.mergeUrl,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({fileId,totalChunks,fileName:this.file.name,fileSize:this.file.size})}).then(res=>res.json()).then(data=>{if(data.code===200){localStorage.removeItem(fileId);// 合并成功,清除进度alert('文件上传完成!');}});}}};
2. 文件夹上传:兼容IE8的“曲线救国”

IE8不支持webkitdirectory,所以只能让用户手动选择文件,并记录相对路径。比如用户选了“文档/报告/2024.docx”,我们通过file.webkitRelativePath(现代浏览器)或让用户输入路径(IE8)来记录层级。

兼容IE8的文件夹路径记录:

// 在handleFileSelect中补充路径记录逻辑handleFileSelect(e){constfiles=e.target.files;for(leti=0;i<files.length;i++){constfile=files[i];// 现代浏览器获取相对路径(如"文档/报告/2024.docx")constrelativePath=file.webkitRelativePath||prompt(`请输入${file.name}的相对路径(如"文档/报告/")`);// IE8手动输入this.files.push({name:file.name,size:file.size,type:file.type,path:relativePath,file:file});}}

三、后端:SpringBoot实现分片合并+加密存储

后端的核心是接收分片、校验完整性、合并文件、加密存储。为了兼容Tomcat6.0(老古董),得用传统的Servlet API,别整Spring MVC的注解(其实Spring Boot 2.x还是支持的,但Tomcat6.0要调低版本)。

1. 分片上传接口(SpringBoot)
// 分片上传控制器:UploadController.java@RestControllerpublicclassUploadController{@Value("${upload.chunk.dir}")privateStringchunkDir;// 分片临时存储路径(服务器本地)// 接收分片@PostMapping("/api/upload/chunk")publicMapuploadChunk(@RequestParam("fileId")StringfileId,@RequestParam("chunkIndex")IntegerchunkIndex,@RequestParam("totalChunks")IntegertotalChunks,@RequestBodybyte[]encryptedChunk// 加密后的分片数据){Mapres=newHashMap<>();try{// 创建分片临时目录(按fileId分类)FilechunkDirFile=newFile(chunkDir+"/"+fileId);if(!chunkDirFile.exists())chunkDirFile.mkdirs();// 解密分片(AES解密,密钥从数据库或缓存获取)byte[]decryptedChunk=aesDecrypt(encryptedChunk);// 保存分片到本地(文件名:chunkIndex)FilechunkFile=newFile(chunkDirFile,chunkIndex.toString());Files.write(chunkFile.toPath(),decryptedChunk);res.put("code",200);res.put("msg","分片上传成功");}catch(Exceptione){res.put("code",500);res.put("msg","分片上传失败:"+e.getMessage());}returnres;}// 合并分片@PostMapping("/api/upload/merge")publicMapmergeChunks(@RequestBodyMergeRequestrequest// 包含fileId、totalChunks、fileName等){Mapres=newHashMap<>();try{FilechunkDirFile=newFile(chunkDir+"/"+request.getFileId());FiletargetFile=newFile("/data/files/"+request.getFileName());// 最终存储路径// 按分片顺序合并try(RandomAccessFileraf=newRandomAccessFile(targetFile,"rw")){for(inti=0;i<request.getTotalChunks();i++){FilechunkFile=newFile(chunkDirFile,i.toString());byte[]data=Files.readAllBytes(chunkFile.toPath());raf.write(data);chunkFile.delete();// 合并后删除临时分片}}// 删除临时分片目录FileUtils.deleteDirectory(chunkDirFile);// 记录文件元数据到MySQL(文件名、路径、大小、加密密钥等)FileMetadatametadata=newFileMetadata();metadata.setFileName(request.getFileName());metadata.setFilePath(targetFile.getPath());metadata.setSize(targetFile.length());metadata.setEncryptKey(getEncryptKey());// 从密钥管理系统获取fileMetadataMapper.insert(metadata);res.put("code",200);res.put("msg","文件合并成功");}catch(Exceptione){res.put("code",500);res.put("msg","文件合并失败:"+e.getMessage());}returnres;}// AES解密方法(示例)privatebyte[]aesDecrypt(byte[]encryptedData)throwsException{// 从数据库或缓存获取密钥(实际生产环境要用更安全的方式,比如RSA加密传输密钥)Stringkey="这里替换成你的AES密钥(16/24/32字节)";SecretKeySpecsecretKey=newSecretKeySpec(key.getBytes(),"AES");Ciphercipher=Cipher.getInstance("AES/CBC/PKCS5Padding");// 提取IV(前16字节)byte[]ivBytes=Arrays.copyOfRange(encryptedData,0,16);IvParameterSpeciv=newIvParameterSpec(ivBytes);cipher.init(Cipher.DECRYPT_MODE,secretKey,iv);// 解密剩余数据byte[]dataBytes=Arrays.copyOfRange(encryptedData,16,encryptedData.length);returncipher.doFinal(dataBytes);}}// MergeRequest.java(合并请求参数)@DatapublicclassMergeRequest{privateStringfileId;privateIntegertotalChunks;privateStringfileName;}
2. 数据库设计(MySQL)

需要一张表存文件元数据,方便后续管理(比如下载、删除)。

CREATETABLEfile_metadata(idINTPRIMARYKEYAUTO_INCREMENT,file_nameVARCHAR(255)NOTNULLCOMMENT'文件名',file_pathVARCHAR(500)NOTNULLCOMMENT'服务器存储路径',sizeBIGINTNOTNULLCOMMENT'文件大小(字节)',encrypt_keyVARCHAR(255)NOTNULLCOMMENT'AES加密密钥',create_timeTIMESTAMPDEFAULTCURRENT_TIMESTAMPCOMMENT'上传时间');

四、兼容性调试:IE8/国产浏览器的“血泪调试”

  1. IE8的XHR兼容:IE8不支持FormData,所以必须用XMLHttpRequest直接传byte[],并且设置Content-Type: application/octet-stream
  2. localStorage容量限制:IE8的localStorage只有5MB,所以只存分片号列表(比如[0,1,2]),别存大文件内容。
  3. 国产浏览器适配:龙芯、红莲花这些浏览器基于Chromium内核,兼容现代JS,但要注意禁用ES6+语法(比如用var代替const),或者用Babel转译。
  4. Tomcat6.0配置:Tomcat6默认不支持Servlet 3.0,所以得把Spring Boot的spring-boot-starter-web换成spring-boot-starter-web-3.0.0.RELEASE(可能需要手动调整依赖版本)。

五、毕业答辩&找工作:稳了!

现在这套代码我在本地跑了整整一周,10G的电影、带1000层文件夹的文档都能上传,断网后重连接着传,加密后的文件用其他工具打不开(密钥正确才能解密)。答辩时老师问“断点续传怎么实现的”“兼容IE8咋处理的”,我直接掏出代码和测试截图,当场给老师演示上传过程——那一刻,我觉得熬夜掉的头发值了!

对了,我建了个QQ群(374992201),专门拉一起做毕设的兄弟。群里有个学长去年做过类似的文件上传系统,把他的踩坑笔记(比如Tomcat6配置、IE8兼容技巧)全分享了。最近群里有活动:新人加群送1~99元红包,推荐同学来帮忙还能拿20%提成——上个月有个兄弟推荐了他的室友,直接拿了500块,够咱吃顿火锅了!

要是你也卡在“大文件上传”这一步,或者想找工作缺个项目经验,不妨进群聊聊。咱不画饼,就唠实在的——代码怎么调,答辩怎么过,工作怎么找,群里全给你扒拉明白!

(最后小声说:要是群里有人能搞出“国产浏览器完美兼容”的补丁,我分他一半红包!)

SQL示例

创建数据库

配置数据库连接

自动下载maven依赖

启动项目

启动成功

访问及测试

默认页面接口定义

在浏览器中访问

数据表中的数据

效果预览

文件上传

文件刷新续传

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

文件夹上传

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

示例下载

下载完整示例

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1163908.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

站群系统如何处理PDF公式转存为XHEDITOR网页格式?

企业网站Word粘贴与导入功能解决方案 项目概述与技术需求 作为山西IT行业的.NET工程师&#xff0c;我们近期接到一个企业网站后台管理系统的升级需求&#xff0c;主要目标是实现Word内容一键粘贴和文档导入功能。这个功能将极大提升客户的内容发布效率&#xff0c;特别是对于…

医疗领域,JAVA大文件上传与下载的示例步骤?

今天早上有网友加我微信&#xff0c;也是咨询这块的技术问题&#xff0c;最近不知道啥情况&#xff0c;加我的网友还是挻多的。实际上我的微信很早就在网上公开了&#xff0c;但是还是有很多网友说找不到。 昨天晚上论坛里面有位网友发私信给我&#xff0c;聊了一下这个问题&am…

汽车制造行业,JAVA如何实现设计图纸的大文件上传示例?

作为国内专注于设计制造领域的软件厂商&#xff0c;近期我们正积极投身于大文件上传下载组件的调研工作。在当前业务场景下&#xff0c;我们有着明确且极具挑战性的需求&#xff1a;所选取的组件必须能够支持高达 100G 文件以及文件夹的上传下载功能&#xff0c;同时要全面适配…

5.1 办公自动化革命:让AI处理90%的重复性文档工作

5.1 办公自动化革命:让AI处理90%的重复性文档工作 在现代职场中,文档处理占据了大量工作时间,从日常邮件撰写到复杂报告编制,从合同审查到数据分析,文档工作无处不在。然而,许多文档任务具有高度重复性和规律性,完全可以借助AI技术实现自动化处理。通过合理运用大语言模…

【文献分享】LyMOI一种结合深度学习和大规模语言模型的用于解读组学数据的工作流程

文章目录介绍代码参考介绍 通过对海量组学数据进行分子全景分析&#xff0c;可以识别细胞中的调控网络&#xff0c;但还需要进行机制解读和实验验证。在此&#xff0c;我们结合深度学习和大型语言模型推理&#xff0c;开发了一种用于组学解读的混合工作流程&#xff0c;称为 L…

别再手动写代码了!Claude Skills 实战,让 AI 帮你干 80% 的活!

&#x1f4cb; 目录 什么是 Claude Skills快速安装 Skills已安装的 Skills 清单Skills 使用方式详解实战案例&#xff1a;使用 Frontend Design Skill 创建网站Skill 管理最佳实践高级技巧常见问题排查 什么是 Claude Skills Claude Skills 是模块化的能力包&#xff0c;包含…

5.3 PPT制作效率爆炸提升:Gamma助力非设计专业也能做出精美演示文稿

5.3 PPT制作效率爆炸提升:Gamma助力非设计专业也能做出精美演示文稿 在职场沟通和商务展示中,演示文稿(PPT)是传递信息、展示观点和影响决策的重要工具。然而,对于大多数非设计专业的职场人士来说,制作一份既美观又专业的PPT往往是一项耗时耗力的任务。从内容组织到视觉设…

5.3 PPT制作效率爆炸提升:Gamma助力非设计专业也能做出精美演示文稿

5.3 PPT制作效率爆炸提升:Gamma助力非设计专业也能做出精美演示文稿 在职场沟通和商务展示中,演示文稿(PPT)是传递信息、展示观点和影响决策的重要工具。然而,对于大多数非设计专业的职场人士来说,制作一份既美观又专业的PPT往往是一项耗时耗力的任务。从内容组织到视觉设…

系统化方法论与实战案例

案例一&#xff1a;数据处理场景 —— 批量清洗 CSV 文件中的无效数据1. 问题定义与需求拆解核心问题某业务场景下有一批用户信息 CSV 文件&#xff08;存储在user_data/目录下&#xff09;&#xff0c;存在三类无效数据&#xff1a;① 关键列&#xff08;user_id、phone&#…

UVM太重了,小项目不需要?

同样一个testbench问题&#xff0c;十个人能给你讲出十种不同的理解方式和答案。SystemVerilog给了我们极大的灵活性&#xff0c;但灵活的代价就是混乱。张三用class写了一套&#xff0c;李四用task搞了另一套&#xff0c;王五直接module堆起来。表面上看都能跑通仿真&#xff…

每日面试题分享140:为什么不选择使用原生的NIO,而是使用Netty?

首先NIO存在一些问题&#xff1a;1、NIO提供了很多接口&#xff0c;适合精细化调用&#xff0c;但是对于通常使用过于复杂&#xff0c;开发难度大效率低。2、NIO存在一些bug&#xff0c;比如Selector空轮询。Netty的优势&#xff1a;1、Netty封装了NIO的API&#xff0c;更明确易…

每日面试题分享140:为什么不选择使用原生的NIO,而是使用Netty?

首先NIO存在一些问题&#xff1a;1、NIO提供了很多接口&#xff0c;适合精细化调用&#xff0c;但是对于通常使用过于复杂&#xff0c;开发难度大效率低。2、NIO存在一些bug&#xff0c;比如Selector空轮询。Netty的优势&#xff1a;1、Netty封装了NIO的API&#xff0c;更明确易…

每日面试题分享141:看过源码吗?说一下Spring有哪些模块?

1、核心容器core、beans、context、sepl2、AOP面向切面编程Spring AOPAspectJ3、数据库交互JDBCTransactions事务ORM4、web层Spring MVCWebFlux5、测试junittest ng

每日面试题分享141:看过源码吗?说一下Spring有哪些模块?

1、核心容器core、beans、context、sepl2、AOP面向切面编程Spring AOPAspectJ3、数据库交互JDBCTransactions事务ORM4、web层Spring MVCWebFlux5、测试junittest ng

[今日战况]前高一步之遥,新品种顶上来!ETF三因子轮动实盘跟踪!股票量化分析工具QTYX-V3.3.5

前言我们的股票量化系统QTYX在实战中不断迭代升级!!!分享QTYX系统目的是提供给大家一个搭建量化系统的模版&#xff0c;帮助大家搭建属于自己的系统。因此我们提供源码&#xff0c;可以根据自己的风格二次开发。 关于QTYX的使用攻略可以查看链接&#xff1a;QTYX使用攻略QTYX一…

5.2 Excel数据处理黑科技:秒级完成以前需要一天的工作量

5.2 Excel数据处理黑科技:秒级完成以前需要一天的工作量 Excel作为最广泛使用的数据处理工具之一,在职场中扮演着重要角色。然而,面对海量数据和复杂分析需求时,传统的Excel操作往往效率低下,处理数万行数据可能需要数小时甚至一整天的时间。随着AI技术与Excel的深度融合…

每日面试题分享142: 什么是Vue的过滤器?有哪些使用场景?

Vue的过滤器是一种数据格式化的功能&#xff0c;主要是文本格式化。在Vue2中使用&#xff0c;在Vue3中被移除了&#xff0c;使用方法和计算属性来替代。主要在双花括号插值和v-bind标签中使用。使用场景&#xff1a;数值格式化文本格式化日期时间格式化列表数据过滤

5.4 智能会议助手:自动记录、总结与任务分配

5.4 智能会议助手:自动记录、总结与任务分配 在现代职场中,会议是企业沟通协作的重要形式,但也是时间成本最高的活动之一。据统计,一个中型企业的员工每周平均花费8-12小时参加会议,而其中相当一部分时间被低效的会议流程所消耗。会议记录整理、要点总结、任务分配等后续…

别再神话 Claude Skills 了:这 12 个“致命”局限性你必须知道

网上有很多介绍 Claude Skills 的文章&#xff0c;但是很少有人提 Skills 的局限性。甚至看到有人稍微把 Skills 吹过头了&#xff01;说实话&#xff0c;Skills 是解决大模型缺乏专业知识、解决上下文窗口等问题的一个先进解法&#xff0c;但目前还不完美。我认为当你无法说出…

5.8 智能日程管理:让AI成为你的个人助理

5.8 智能日程管理:让AI成为你的个人助理 在快节奏的现代职场中,时间管理已成为每个人必须掌握的核心技能。无论是企业高管还是普通员工,每天都需要处理大量的会议、任务、截止日期和各种突发事件,如何高效地安排和利用时间直接影响着工作成效和个人发展。传统的日程管理方…