news 2026/5/2 12:17:25

银行系统中,SpringBoot如何实现百M级别大文件的上传下载性能优化?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
银行系统中,SpringBoot如何实现百M级别大文件的上传下载性能优化?

大文件传输解决方案设计 - 专业分析报告

项目背景与需求分析

作为福建某上市集团项目负责人,我认识到我们当前面临的大文件传输需求具有以下关键特性:

  1. 超大文件支持:需要稳定传输50G以上文件,文件夹需保持层级结构
  2. 高稳定性要求:必须支持断点续传且进度信息持久化
  3. 安全性要求:需支持SM4国密和AES加密,满足信创国产化环境
  4. 兼容性挑战:需支持IE8在内的多种浏览器及国产操作系统
  5. 部署灵活性:需同时支持私有和公有云部署模式
  6. 长期维护:需要源代码授权以便集团内部长期使用和维护

技术架构设计

整体架构

[客户端浏览器] ←HTTPS→ [Nginx反向代理] ←→ [SpringBoot应用服务层] ↑ ↓ [阿里云OSS] ←→ [文件传输服务] ←→ [数据库集群]

关键技术选型

  1. 前端技术栈

    • 基于Vue2 CLI框架扩展
    • 采用分片上传+WebWorker实现大文件处理
    • 使用IndexedDB存储本地断点信息
  2. 后端技术栈

    • SpringBoot 2.7.x
    • 阿里云OSS SDK(兼容国产对象存储)
    • 国密SM4加密算法实现
    • 多数据库支持抽象层
  3. 存储方案

    • 主存储:阿里云OSS
    • 元数据存储:支持SQL Server/MySQL/Oracle/达梦/人大金仓

核心功能实现代码

前端关键代码片段

文件分片上传组件 (FileChunkUploader.vue)
exportdefault{data(){return{fileList:[],chunkSize:5*1024*1024,// 5MB分片concurrentLimit:3,uploadStatus:{}}},methods:{asynchandleUpload(file){// 初始化上传状态constfileId=this.generateFileId(file)awaitthis.initUploadSession(file,fileId)// 读取文件分片constchunks=this.createFileChunks(file)// 使用WebWorker进行分片上传constworker=newWorker('/js/upload.worker.js')worker.postMessage({fileId,chunks,url:'/api/upload/chunk'})worker.onmessage=(e)=>{this.updateUploadProgress(e.data)}},createFileChunks(file){constchunks=[]letstart=0while(start<file.size){constend=Math.min(start+this.chunkSize,file.size)chunks.push({file:file.slice(start,end),chunkNumber:chunks.length+1,totalChunks:Math.ceil(file.size/this.chunkSize)})start=end}returnchunks},asyncinitUploadSession(file,fileId){// 检查IndexedDB中是否有未完成的上传constsavedProgress=awaitthis.checkSavedProgress(fileId)if(savedProgress){returnsavedProgress}// 初始化服务端上传会话constresponse=awaitaxios.post('/api/upload/init',{fileName:file.name,fileSize:file.size,fileId,chunkSize:this.chunkSize})// 保存到IndexedDBawaitthis.saveToIndexedDB({fileId,fileName:file.name,fileSize:file.size,chunkSize:this.chunkSize,uploadedChunks:[],...response.data})returnresponse.data}}}
IE8兼容处理 (legacy.js)
// 使用Flash作为IE8备选方案if(typeofFileReader==='undefined'){swfobject.embedSWF("/static/uploader.swf","flash-uploader","100%","100%","10.0.0","/static/expressInstall.swf",{chunkSize:5242880,uploadUrl:"/api/upload/flash"},{allowScriptAccess:"always",wmode:"transparent"});}

后端关键代码片段

文件上传控制器 (FileUploadController.java)
@RestController@RequestMapping("/api/upload")publicclassFileUploadController{@AutowiredprivateFileUploadServicefileUploadService;@PostMapping("/init")publicResponseEntityinitUploadSession(@RequestBodyFileUploadInitRequestrequest){UploadSessionsession=fileUploadService.initUploadSession(request.getFileId(),request.getFileName(),request.getFileSize(),request.getChunkSize());returnResponseEntity.ok(session);}@PostMapping("/chunk")publicResponseEntityuploadChunk(@RequestParam("file")MultipartFilefile,@RequestParam("chunkNumber")intchunkNumber,@RequestParam("totalChunks")inttotalChunks,@RequestParam("fileId")StringfileId){fileUploadService.saveChunk(fileId,chunkNumber,file.getInputStream());UploadProgressprogress=fileUploadService.getUploadProgress(fileId);returnResponseEntity.ok(progress);}@PostMapping("/complete")publicResponseEntitycompleteUpload(@RequestBodyFileUploadCompleteRequestrequest){FileInfofileInfo=fileUploadService.completeUpload(request.getFileId(),request.getChunksHash());returnResponseEntity.ok(fileInfo);}}
文件传输服务 (FileUploadServiceImpl.java)
@ServicepublicclassFileUploadServiceImplimplementsFileUploadService{@AutowiredprivateOSSossClient;@AutowiredprivateUploadSessionRepositorysessionRepository;@Value("${oss.bucket-name}")privateStringbucketName;@OverridepublicUploadSessioninitUploadSession(StringfileId,StringfileName,longfileSize,intchunkSize){UploadSessionsession=newUploadSession();session.setFileId(fileId);session.setFileName(fileName);session.setFileSize(fileSize);session.setChunkSize(chunkSize);session.setStatus(UploadStatus.IN_PROGRESS);session.setCreatedAt(newDate());// 初始化OSS分片上传InitiateMultipartUploadRequestrequest=newInitiateMultipartUploadRequest(bucketName,"uploads/"+fileId);InitiateMultipartUploadResultresult=ossClient.initiateMultipartUpload(request);session.setUploadId(result.getUploadId());returnsessionRepository.save(session);}@OverridepublicvoidsaveChunk(StringfileId,intchunkNumber,InputStreamchunkStream){UploadSessionsession=sessionRepository.findByFileId(fileId).orElseThrow(()->newRuntimeException("Upload session not found"));// 上传分片到OSSUploadPartRequestrequest=newUploadPartRequest();request.setBucketName(bucketName);request.setKey("uploads/"+fileId);request.setUploadId(session.getUploadId());request.setPartNumber(chunkNumber);request.setInputStream(chunkStream);request.setPartSize(session.getChunkSize());UploadPartResultresult=ossClient.uploadPart(request);// 保存分片信息session.getUploadedParts().add(newUploadedPart(chunkNumber,result.getPartETag()));sessionRepository.save(session);}@OverridepublicFileInfocompleteUpload(StringfileId,StringchunksHash){UploadSessionsession=sessionRepository.findByFileId(fileId).orElseThrow(()->newRuntimeException("Upload session not found"));// 验证所有分片if(!validateChunks(session,chunksHash)){thrownewRuntimeException("Chunks validation failed");}// 完成OSS分片上传CompleteMultipartUploadRequestrequest=newCompleteMultipartUploadRequest(bucketName,"uploads/"+fileId,session.getUploadId(),session.getUploadedParts().stream().map(p->newPartETag(p.getPartNumber(),p.getETag())).collect(Collectors.toList()));CompleteMultipartUploadResultresult=ossClient.completeMultipartUpload(request);// 加密存储文件信息FileInfofileInfo=newFileInfo();fileInfo.setFileId(fileId);fileInfo.setFileName(session.getFileName());fileInfo.setFileSize(session.getFileSize());fileInfo.setFileUrl(result.getLocation());fileInfo.setStorageType("OSS");fileInfo.setEncrypted(true);fileInfo.setEncryptionAlgorithm("SM4");// 保存文件元数据returnfileInfoRepository.save(fileInfo);}}
国密SM4加密工具类 (SM4Util.java)
publicclassSM4Util{privatestaticfinalStringALGORITHM_NAME="SM4";privatestaticfinalStringDEFAULT_KEY="default_key_1234";// 生产环境应从配置读取publicstaticbyte[]encrypt(byte[]data,Stringkey){try{Ciphercipher=Cipher.getInstance(ALGORITHM_NAME);SecretKeySpecsecretKey=newSecretKeySpec(key.getBytes(),ALGORITHM_NAME);cipher.init(Cipher.ENCRYPT_MODE,secretKey);returncipher.doFinal(data);}catch(Exceptione){thrownewRuntimeException("SM4 encryption failed",e);}}publicstaticbyte[]decrypt(byte[]encryptedData,Stringkey){try{Ciphercipher=Cipher.getInstance(ALGORITHM_NAME);SecretKeySpecsecretKey=newSecretKeySpec(key.getBytes(),ALGORITHM_NAME);cipher.init(Cipher.DECRYPT_MODE,secretKey);returncipher.doFinal(encryptedData);}catch(Exceptione){thrownewRuntimeException("SM4 decryption failed",e);}}}

系统特色功能实现

1. 文件夹层级结构保持

// 文件夹上传处理publicclassFolderUploadProcessor{publicvoiduploadFolder(Filefolder,StringparentPath){File[]files=folder.listFiles();if(files!=null){for(Filefile:files){StringcurrentPath=parentPath+"/"+file.getName();if(file.isDirectory()){// 创建文件夹标记createFolderMarker(currentPath);// 递归上传子文件夹uploadFolder(file,currentPath);}else{// 上传文件uploadFile(file,currentPath);}}}}privatevoidcreateFolderMarker(Stringpath){// 在OSS中创建0字节文件作为文件夹标记ObjectMetadatametadata=newObjectMetadata();metadata.setContentLength(0);ossClient.putObject(bucketName,path+"/.folder",newByteArrayInputStream(newbyte[0]),metadata);}}

2. 多数据库支持抽象层

// 数据库配置抽象publicinterfaceDatabaseConfig{DataSourcecreateDataSource();StringgetDialect();}// 达梦数据库实现publicclassDamengConfigimplementsDatabaseConfig{@OverridepublicDataSourcecreateDataSource(){DruidDataSourcedataSource=newDruidDataSource();dataSource.setDriverClassName("dm.jdbc.driver.DmDriver");dataSource.setUrl("jdbc:dm://host:port/database");dataSource.setUsername("user");dataSource.setPassword("password");returndataSource;}@OverridepublicStringgetDialect(){return"dm";}}// 动态数据源路由publicclassDynamicDataSourceextendsAbstractRoutingDataSource{@OverrideprotectedObjectdetermineCurrentLookupKey(){returnDatabaseContextHolder.getDatabaseType();}}

性能优化措施

  1. 分片大小动态调整

    • 根据网络状况自动调整分片大小(5MB-20MB)
    • 大文件使用较大分片减少请求数
    • 不稳定网络使用较小分片提高成功率
  2. 并发控制

    • 前端限制并发上传数(3-5个并发)
    • 后端使用线程池处理上传请求
  3. 缓存优化

    • 使用Redis缓存频繁访问的文件元数据
    • 实现本地文件缓存减少OSS访问
  4. 压缩传输

    • 对大文本文件启用GZIP压缩
    • 图片/视频等二进制文件跳过压缩

安全防护方案

  1. 传输安全

    • 强制HTTPS传输
    • 支持国密SSL协议
  2. 数据加密

    • 传输加密:SM4/AES
    • 存储加密:服务端二次加密
  3. 访问控制

    • 基于角色的权限管理(RBAC)
    • IP白名单限制
    • 文件访问签名验证
  4. 审计日志

    • 完整操作日志记录
    • 文件访问轨迹追踪

信创环境适配方案

  1. 国产操作系统适配

    • 提供统信UOS/麒麟系统的安装包
    • 系统调用兼容层
  2. 国产浏览器支持

    • 专用插件处理特殊浏览器需求
    • 降级方案确保基本功能可用
  3. 国产数据库适配

    • 达梦/人大金仓方言处理
    • 特殊SQL语法转换
  4. 国产中间件支持

    • 东方通等国产中间件适配
    • 国密算法硬件加速支持

部署架构建议

内网部署方案

[客户端] → [防火墙] → [负载均衡] → [应用集群] ↓ [数据库集群] ←→ [存储集群]

混合云部署方案

[内网客户端] → [专属网关] → [公有云VPC] ↑ [外网客户端] → [安全接入]

项目交付建议

  1. 源代码交付

    • 完整可编译的源代码
    • 详细架构文档
    • 自动化构建脚本
  2. 知识转移

    • 核心技术培训(8-16课时)
    • 二次开发指南
    • 常见问题解决方案手册
  3. 质量保证

    • 完整的测试用例(单元测试覆盖率>80%)
    • 性能测试报告
    • 安全渗透测试报告
  4. 后续支持

    • 6个月免费技术支持
    • 紧急问题响应机制
    • 定期版本更新

预算与实施计划

  1. 开发成本估算

    • 核心功能开发:80人日
    • 信创适配:30人日
    • 测试与优化:20人日
    • 文档编写:10人日
  2. 实施时间表

    • 需求分析与设计:2周
    • 核心功能开发:6周
    • 信创环境适配:2周
    • 测试与调优:2周
    • 交付与培训:1周
  3. 预算分配

    • 源代码采购:120万
    • 定制开发:20万
    • 培训与支持:10万

此方案全面考虑了贵司提出的各项技术要求,特别是在信创环境适配、超大文件传输和安全性方面提供了专业解决方案。建议选择有政府项目经验的供应商合作,确保项目顺利实施。

SQL示例

创建数据库

配置数据库连接

自动下载maven依赖

启动项目

启动成功

访问及测试

默认页面接口定义

在浏览器中访问

数据表中的数据

效果预览

文件上传

文件刷新续传

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

文件夹上传

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

批量下载

支持文件批量下载

下载续传

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

文件夹下载

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

示例下载

下载完整示例

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

Wijmo管理 JavaScript 应用程序中的混乱数据

管理 JavaScript 应用程序中的混乱数据2026年2月2日使用 Wijmo 的 JavaScript DataGrid 将杂乱的数据转换为清晰、一致且易于处理的信息。Wijmo 是一套先进的 JavaScript UI 控件集合&#xff0c;包含 100 多个高性能控件&#xff0c;专为现代企业应用程序而设计。Wijmo 兼顾速…

作者头像 李华
网站建设 2026/4/29 19:13:38

能力解耦:像瑞幸卖咖啡一样卖SaaS

《ToB深水区的生存法则》 第二模块:加固船体——关于“系统”的内功心法(6/12) 朋友,又见面了。 上回咱们聊完“治理内耗”,老张回去挺当回事,搞了匿名吐槽,开了清淤会,团队里的“熵”算是降下来一点,至少扯皮少了,信息也透明了些。他挺高兴,觉得船体结实了不少。 …

作者头像 李华
网站建设 2026/4/28 13:42:04

U-Boot 核心作用与核心知识点

一、核心作用&#xff08;精准提炼&#xff09; 硬件初始化&#xff1a;上电后优先初始化 DDR、GPIO、EMMC/SD、网络等关键外设&#xff0c;为 Linux 内核提供可运行的硬件环境&#xff08;裸机层核心工作&#xff09;。内核引导&#xff1a;从 EMMC/SD 卡 / 网络等介质加载 L…

作者头像 李华
网站建设 2026/5/2 12:13:35

端口保护电路简略

一个完整的、可直接用于PCB设计的带器件原理图&#xff0c;包含详细的元件型号、参数和连接方式。 &#x1f6e1;️ 完整模拟输入保护电路原理图&#xff08;带具体器件&#xff09; ┌──────────────────────────────────────────…

作者头像 李华
网站建设 2026/4/15 19:38:13

如何理解AI原生企业的核心定义与价值?

当越来越多企业在会议室里讨论“要不要上 AI”“要不要做智能体”时&#xff0c;现实世界的生产现场却显得有些冷静。排产依然靠经验&#xff0c;工艺仍靠老师傅&#xff0c;系统之间的数据还在来回倒腾。AI 很热&#xff0c;但真正跑进企业肌理里的&#xff0c;很少。 这正是…

作者头像 李华