当前位置: 首页 > news >正文

spring boot 实现Minio分片上传

应用场景

分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块(我们称之为Part)来进行分别上传,上传完之后再由服务端对所有上传的文件进行汇总整合成原始的文件。

分片上传的场景

  • 大文件上传

  • 网络环境环境不好,存在需要重传风险的场景

分片上传的步骤

没有
前端上传文件的MD5值
判断是否上传过文件
创建文件存储用于存储分块
前端上传文件的MD5值和分块文件的序号
通过序号判断是否包含该分块
前端上传分块
存储分块
是否是最后一块
合并分块
返回文件的存储路径

检查文件的代码

在文件第一次上传时,上传文件的md5值,从而判断文件是否存在minio中

public Result<Boolean> checkFile(String fileMd5) {//正常做业务时应该先从数据库中查询//如果数据库存在再查询 minioGetObjectArgs getObjectArgs = GetObjectArgs.builder().bucket(bucketName)//                    todo 这里固定了文件的后缀,实际情况下应该从数据库开始查询,得到文件的路径.object(getFilePathByMd5(fileMd5,"png")).build();//查询远程服务获取到一个流对象try {FilterInputStream inputStream = minioClient.getObject(getObjectArgs);if(inputStream!=null){//文件已存在return Result.success(true);}} catch (Exception e) {e.printStackTrace();}//文件不存在return Result.success(false);}

检查分块的代码

检查分块是前端把需要上传的文件经过大小计算后,算出分块的数量,然后把循环发送文件的md5值和分块序号,然后在minio中检查对应文件夹下是否有对应的分块,如果检查到某一处没有对应的分块,便知道传输中断的位置。

 public Result<Boolean> checkChunk(String fileMd5, int chunkIndex) {//根据md5得到分块文件所在目录的路径String chunkFileFolderPath = getChunkFileFolderPath(fileMd5);//如果数据库存在再查询 minioGetObjectArgs getObjectArgs = GetObjectArgs.builder().bucket(bucketName).object(chunkFileFolderPath+chunkIndex).build();//查询远程服务获取到一个流对象try {FilterInputStream inputStream = minioClient.getObject(getObjectArgs);if(inputStream!=null){//文件已存在return Result.success(true);}} catch (Exception e) {e.printStackTrace();}//文件不存在return Result.success(false);}

上传分块的代码

    public Result uploadChunk(String fileMd5, int chunk, String localChunkFilePath) {//分块文件的路径String chunkFilePath = getChunkFileFolderPath(fileMd5) + chunk;//获取mimeTypeString mimeType = localChunkFilePath.substring(localChunkFilePath.lastIndexOf("."));//将分块文件上传到minioboolean b = addMediaFilesToMinIO(localChunkFilePath, mimeType, bucketName, chunkFilePath);if(!b){return Result.error("上传分块文件失败");}//上传成功return Result.success(true);}

合并分块的代码

合并分块文件之前,需要检查文件是否和源文件相同,我们通过把分块合并后取文件的md5值和传输过来的MD5值作比较,如果相同则证明传输正确,把合并后的文件存入minio中,并清除分块文件

public Result mergechunks(String fileMd5, int chunkTotal) {//分块文件所在目录String chunkFileFolderPath = getChunkFileFolderPath(fileMd5);//找到所有的分块文件List<ComposeSource> sources = Stream.iterate(0, i -> ++i).limit(chunkTotal).map(i -> ComposeSource.builder().bucket(bucketName).object(chunkFileFolderPath + i).build()).collect(Collectors.toList());//合并后文件的objectnameString objectName = getFilePathByMd5(fileMd5, "png");//指定合并后的objectName等信息ComposeObjectArgs composeObjectArgs = ComposeObjectArgs.builder().bucket(bucketName).object(objectName)//合并后的文件的objectname.sources(sources)//指定源文件.build();//===========合并文件============//报错size 1048576 must be greater than 5242880,minio默认的分块文件大小为5Mtry {minioClient.composeObject(composeObjectArgs);} catch (Exception e) {e.printStackTrace();log.error("合并文件出错,bucket:{},objectName:{},错误信息:{}",bucketName,objectName,e.getMessage());return Result.error("合并文件异常");}//===========校验合并后的和源文件是否一致,视频上传才成功===========//先下载合并后的文件File file = downloadFileFromMinIO(bucketName, objectName);try(FileInputStream fileInputStream = new FileInputStream(file)){//计算合并后文件的md5String mergeFile_md5 = DigestUtils.md5Hex(fileInputStream);//比较原始md5和合并后文件的md5if(!fileMd5.equals(mergeFile_md5)){log.error("校验合并文件md5值不一致,原始文件:{},合并文件:{}",fileMd5,mergeFile_md5);return Result.error("文件校验失败");}}catch (Exception e) {return Result.error("文件校验失败");}//==============将文件信息入库============
//        在做业务时要将得到的路径存入数据库//==========清理分块文件=========clearChunkFiles(chunkFileFolderPath,chunkTotal);return Result.success(true);}/*** 清除分块文件* @param chunkFileFolderPath 分块文件路径* @param chunkTotal 分块文件总数*/private void clearChunkFiles(String chunkFileFolderPath,int chunkTotal){Iterable<DeleteObject> objects =  Stream.iterate(0, i -> ++i).limit(chunkTotal).map(i -> new DeleteObject(chunkFileFolderPath+ i)).collect(Collectors.toList());;RemoveObjectsArgs removeObjectsArgs = RemoveObjectsArgs.builder().bucket(bucketName).objects(objects).build();Iterable<io.minio.Result<DeleteError>> results = minioClient.removeObjects(removeObjectsArgs);//要想真正删除results.forEach(f->{try {DeleteError deleteError = f.get();} catch (Exception e) {e.printStackTrace();}});}

相关文章:

spring boot 实现Minio分片上传

应用场景 分片上传&#xff0c;就是将所要上传的文件&#xff0c;按照一定的大小&#xff0c;将整个文件分隔成多个数据块&#xff08;我们称之为Part&#xff09;来进行分别上传&#xff0c;上传完之后再由服务端对所有上传的文件进行汇总整合成原始的文件。 分片上传的场景…...

2023年09月 C/C++(六级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C编程&#xff08;1~8级&#xff09;全部真题・点这里 Python编程&#xff08;1~6级&#xff09;全部真题・点这里 第1题&#xff1a;生日相同 在一个有180人的大班级中&#xff0c;存在两个人生日相同的概率非常大&#xff0c;现给出每个学生的名字&#xff0c;出生月日。试…...

docker-compose 部署示例

文章目录 docker-compose文件格式docker-compose 下载 docker-compose文件格式 这个软件的实际很小&#xff0c;只是根据配置文件产生一些docker命令来执行可以。 配置文件本身是yml的格式&#xff0c;如下 version: 3.5services:# Etherpad: real-time collaborative docume…...

新版WordPress插件短视频去水印小程序源码

最新版去水印小程序源码&#xff0c;本版本全开源&#xff0c;是WordPress插件 上传到Wordpress 安装插件 启动之后 绑定自己的小程序id wordpress可以在宝塔一键部署 也可以用我的这个 搭建前我们需要一下东西&#xff1a; 第一个&#xff1a;一台服务器&#xff08;国内外都可…...

如何提高MES系统的落地成功率?

导 读 ( 文/ 2768 ) 制造执行系统&#xff08;MES&#xff09;在现代制造业中扮演着至关重要的角色&#xff0c;但实施MES系统并取得成功并非易事。为了帮助企业提高MES系统的落地成功率&#xff0c;本文将介绍关键的方法和策略。通过深入了解业务需求、有效的团队合作、全面的…...

private key ssh连接服务器

这里用到的软件是PuTTY。 https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html 保存本地rsa文件后&#xff0c;打开软件PuTTYgen&#xff0c;点击Load导入文件&#xff0c;输入Key passphrase即密码&#xff0c;保存至本地。 随后在PuTTY配置ssh的用户名 来Cred…...

PDF-Word-图片等的互相转换

轻闪PDF客户端 - 功能强大的一站式PDF工具 | PDF编辑、转换、阅读 上面页面支持PDF转换成各类别&#xff1a;鼠标停留在PDF工具&#xff0c;点击转换类型即可在线转换 Word-PDF&#xff1a;word文档打开word文件中&#xff0c;点击文件->另存为->另存为的位置->保存…...

【VR开发】【Unity】0-课程简介和概述

【说明】 这是我录制的一套VR基础开发课程的文字版本&#xff0c;更加便于快速参考。 应大家在后台所提的需求&#xff0c;从今天开始&#xff0c;我计划带给大家一套完整达40课时的VR开发基础课程。 在开始学习前需要注意如下几点&#xff1a; 本教程基于Unity2022.2.1f1版…...

Java面试题-Java核心基础-第三天(基本数据类型)

目录 一、Java的基本数据类型了解吗&#xff1f; 二、基本类型和包装类型的区别 三、包装类型的缓存机制了解吗&#xff1f; 四、自动拆箱和自动装箱了解吗&#xff1f; 五、为什么浮点数在运算的时候会有精度损失的风险&#xff1f; 六、如何解决浮点数在运算时存在的精度…...

Bean容器里的单例是根据什么识别它是同一个类呢?(比如容器里创建了A类,再去用这个A类的时候,Bean容器怎么知道这个就是A类?)

Spring容器中的Bean的识别主要依赖于Bean的名称&#xff08;ID&#xff09;和类型。以下是详细解释&#xff1a; Bean的名称&#xff08;ID&#xff09;&#xff1a;每个Bean在Spring容器中都必须有一个唯一的名称&#xff08;ID&#xff09;。这个名称通常在配置文件中、Java…...

简述 happens - before 八大规则

“Happens-Before” 是Java内存模型中的概念&#xff0c;用于描述多线程程序中操作之间的顺序和可见性关系。它定义了一组规则&#xff0c;哪些操作具有可预测的行为。以下是"Happens-Before" 的八大规则&#xff1a; 程序顺序规则&#xff08;Program Order Rule&am…...

windows flask 多进程高并发

最近在做的一个项目&#xff0c;需要将十几个python函数封装程flask服务供外界调用&#xff0c;每个函数之间没有什么关系&#xff0c;相互独立。虽然感觉不是很难&#xff0c;但因为用的windows系统&#xff0c;遇到的坑比较多&#xff0c;在此一一总结一下。 flask偶尔出现卡…...

【设计模式】十、组合模式

文章目录 案例组合模式基本介绍类图代码 组合模式在 JDK 集合的源码分析组合模式的注意事项和细节 案例 编写程序展示一个学校院系结构&#xff1a;需求是这样&#xff0c;要在一个页面中展示出学校的院系组成&#xff0c;一个学校有多个学院&#xff0c;一个学院有多个系。如…...

React知识点系列(8)-每天10个小知识

目录 1. 在 React 中&#xff0c;什么是受控组件和非受控组件&#xff1f;请解释一下它们之间的区别和适用场景。2. 如何使用 React 的 useReducer Hook 来管理组件状态&#xff1f;请描述一下 useReducer 的工作原理和适用场景。工作原理&#xff1a;适用场景&#xff1a; 3. …...

rust注释

一、普通注释 // 这是第一种注释方式/* 这是第二种注释方式 */ /* 多行注释 多行注释 多行注释*/二、文档注释 ///外部行文档注释。为接下来的项生成帮助文档 //! 内部行文档注释。为注释所属于的项生成帮助文档/**...*/外部块文档注释。为接下来的项生成帮助文档 /*!...*/内…...

【Java学习之道】GUI开发的基本概念

引言 在这一章&#xff0c;我们将一起走进Java的图形用户界面&#xff08;GUI&#xff09;开发的世界。在你阅读完这篇文章后&#xff0c;你将能够了解什么是GUI&#xff0c;以及如何使用Java进行GUI的开发。 一、什么是GUI 首先&#xff0c;让我们来解答一个许多初学者都会…...

Docker部署gitlab_ce(避坑版---社区版)

1 下载docker 2 下载gitlab镜像 3 运行 4 进入容器内部修改 5 在浏览器里访问 6 修改root密码&#xff08;如果忘记请修改&#xff09; 1 下载docker # 安装依赖 yum install -y yum-utils device-mapper-persistent-data lvm2# 设置yum源 yum-config-manager --add-repo https…...

数据仓库DW-理论知识储备

数据仓库DW 数据仓库具备 采集数据、分析数据、存储数据的功能&#xff0c;最后得出一些有用的数据&#xff0c;一些目标数据来使用。 采集来自不同源的数据&#xff0c;然后对这些数据进行分析和计算得出一些有用的指标&#xff0c;提供数据决策支持。 数据的来源有&#xff…...

SpringBoot 如何优雅的停机

这里写目录标题 1 介绍2 使用2.1 开启 hook2.2 禁用 hook 3 手动指定 hook 1 介绍 SpringBoot 如果需要使用hook则需要开启spring.main.register-shutdown-hooktrue(默认为true) 如果使用kill -9则不会出发JVM的hook&#xff0c;kill可以正常触发hook server:port: 8080shutd…...

详细教程:Postman 怎么调试 WebSocket

WebSocket 是一个支持双向通信的网络协议&#xff0c;它在实时性和效率方面具有很大的优势。Postman 是一个流行的 API 开发工具&#xff0c;它提供了许多功能来测试和调试 RESTful API 接口&#xff0c;最新的版本也支持 WebSocket 接口的调试。想要学习更多关于 Postman 的知…...

【NotebookLM文学研究辅助终极指南】:20年数字人文专家亲授3大高阶用法,92%学者忽略的文本洞察捷径

更多请点击&#xff1a; https://kaifayun.com 第一章&#xff1a;NotebookLM文学研究辅助的范式革命 传统文学研究长期依赖人工精读、笔记摘录与跨文本比对&#xff0c;耗时且易受主观经验局限。NotebookLM 的引入&#xff0c;标志着从线性阅读向语义驱动、上下文感知、可追溯…...

保姆级教程:用Vue3+webrtc-streamer搞定海康/大华监控的Web实时播放(附完整代码)

Vue3与WebRTC-streamer实战&#xff1a;企业级监控视频流集成指南 监控系统在现代企业管理中扮演着重要角色&#xff0c;而将监控视频无缝集成到Web应用中已成为许多开发者的刚需。本文将带你从零开始&#xff0c;使用Vue3和webrtc-streamer实现海康、大华等主流监控设备的实时…...

2026年IPA防破解安全加固公司怎么选?这份iOS加固服务商横向对比清单请收好

当你的iOS应用核心代码被逆向、商业逻辑被剽窃、盗版版本在分发平台泛滥时&#xff0c;寻找一家靠谱的IPA防破解安全加固公司就成了技术负责人的当务之急。但面对市面上众多服务商&#xff0c;如何判断哪家方案真正有效&#xff0c;且不影响App Store过审&#xff1f;本文基于多…...

百度文心大模型如何通过Taotoken实现稳定API调用与成本控制

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 百度文心大模型如何通过Taotoken实现稳定API调用与成本控制 对于希望集成百度文心大模型进行内容生成的企业开发者而言&#xff0c…...

命令行视频生成工具tubecli:配置即代码的自动化视频制作实践

1. 项目概述与核心价值如果你经常需要处理视频内容&#xff0c;无论是做自媒体、产品演示还是内部培训&#xff0c;大概率都遇到过这样的场景&#xff1a;手头有一堆素材、脚本或者PPT&#xff0c;但把它们变成一段流畅的视频&#xff0c;总得在剪辑软件里折腾半天。更别提批量…...

Python自动化资源管理工具closeclaw:智能清理闲置窗口与进程

1. 项目概述与核心价值最近在GitHub上看到一个挺有意思的项目&#xff0c;叫closeclaw&#xff0c;作者是krishpranav。乍一看这个仓库名&#xff0c;你可能会有点摸不着头脑——“关闭爪子”&#xff1f;这到底是干嘛的&#xff1f;点进去研究了一番&#xff0c;发现这是一个用…...

从原理到实战:拆解LCR表如何实现0.1%精度的电容测量(附寄生效应消除指南)

从原理到实战&#xff1a;拆解LCR表如何实现0.1%精度的电容测量&#xff08;附寄生效应消除指南&#xff09; 在电子工程领域&#xff0c;精确测量电容值是一项基础却极具挑战性的任务。无论是研发高频电路的设计师&#xff0c;还是调试精密仪表的工程师&#xff0c;亦或是研究…...

从蓝牙4.2到5.4:广播包格式的‘进化史’与向后兼容那些坑

蓝牙广播协议演进史&#xff1a;从4.2到5.4的兼容性实战指南 当你的智能手表突然无法被旧款手机发现&#xff0c;或者工业传感器在新版本固件下出现广播丢包——这些看似简单的连接问题背后&#xff0c;往往隐藏着蓝牙协议版本迭代带来的兼容性暗礁。作为无线通信领域的"毛…...

终极Windows离线语音识别指南:打造企业级隐私安全的实时字幕系统

终极Windows离线语音识别指南&#xff1a;打造企业级隐私安全的实时字幕系统 【免费下载链接】TMSpeech 腾讯会议摸鱼工具 项目地址: https://gitcode.com/gh_mirrors/tm/TMSpeech 在数字化办公和远程协作日益普及的今天&#xff0c;实时语音转文字技术已成为提升工作效…...

如何用JavaScript解放双手:AutoJs6让Android自动化变得简单有趣

如何用JavaScript解放双手&#xff1a;AutoJs6让Android自动化变得简单有趣 【免费下载链接】AutoJs6 安卓平台 JavaScript 自动化工具 (Auto.js 二次开发项目) 项目地址: https://gitcode.com/gh_mirrors/au/AutoJs6 你是否厌倦了每天在手机上重复点击相同的按钮&#…...