minio spring boot 秒传、分片上传、断点续传文件实现
此处后端使用的是前期封装的自定义starter,具体链接可参考:minio对象存储spring boot starter封装组件
这里主要针对前期封装的组件,做一个简单的应用,前端直传可查看之前的文章
秒传
秒传的逻辑比较简单,在前传上传之前,先获取到对应文件的md5,传给后端,后端校验md5是否已经存在,存在则直接提示上传成功,否则,发起文件上传请求
获取文件MD5,前端可以使用spark-md5
或者crypto-js
<el-upload class="upload-demo" drag action="#" :http-request="sparkUploadHandle" :show-file-list="false"><el-icon class="el-icon--upload"><UploadFilled /></el-icon><div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
</el-upload>
对应的处理逻辑
<script setup lang="ts">
import { ElMessage } from 'element-plus'
import SparkMD5 from 'spark-md5'
import { checkMd5 } from '@/api/file'
import { UploadFilled } from '@element-plus/icons-vue'const sparkUploadHandle = (param: any) => {const file = param.fileconst fileReader = new FileReader()const Spark = new SparkMD5.ArrayBuffer()fileReader.readAsArrayBuffer(file)fileReader.onload = function (e) {Spark.append(e.target.result)const md5 = Spark.end()ElMessage.success('文件MD5:' + md5)//上传逻辑处理const data = {md5: md5,fileName: file.name}checkMd5(data).then(resp => {if (resp.code == 201) {ElMessage.success('秒传成功')} else {ElMessage.info('后台无数据,正在上传中....')//请求上传接口}})}
}
</script>
checkMd5
就是请求后端接口,查看是否存在
分片上传
这里使用的是前端直传方式的分片上传,处理逻辑:前端根据指定的大小对文件进行分片,分片完成后,根据文件名和分片数量去请求后端,获得对应的分片上传地址集合,再根据返回的地址集合,进行前端直传,传完后,调用后端接口,合并分片
后端接口
后端拿到对应的文件名称,分片大小和文件类型,然后返回给前端对应的put直传地址集合,每个直传地址默认10分钟的有效期
@Autowiredprivate MinioService minioService;@GetMapping("/part-url")public RestResult<MultiPartUploadInfo> partUrl(@RequestParam String fileName,@RequestParam int partSize, @RequestParam String contentType) throws MinioException {MultiPartUploadInfo uploadInfo = minioService.initMultiPartUploadId("bucketName", fileName, partSize, contentType);return RestResult.ok(uploadInfo);}@GetMapping("/merge-part")public RestResult<String> mergePart(@RequestParam String fileName, @RequestParam String uploadId) throws MinioException {String merge = minioService.mergeMultiPartUpload("bucketName", fileName, uploadId);return RestResult.ok(merge);}
前端
<el-upload class="upload-demo" drag action="#" :http-request="partUploadHandle" :show-file-list="false"><el-icon class="el-icon--upload"><UploadFilled /></el-icon><div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
</el-upload>
import { reactive } from 'vue'
import service from '@/utils/request'
import { getPartUrl, mergePart } from '@/api/file'
import { UploadFilled } from '@element-plus/icons-vue'const state = reactive({uploadId: ''
})
//分片大小
const chunkSize = 50 * 1024 * 1024const partUploadHandle = (param: any) => {let file = param.file// 正在创建分片let fileChunks = createFileChunk(file)let data = {fileName: file.name,partSize: fileChunks.length,contentType: file.type}//获得上传的urlgetPartUrl(data).then(resp => {state.uploadId = resp.data.uploadIdlet uploadUrls = resp.data.uploadUrlsif (fileChunks.length !== uploadUrls.length) {ElMessage.error('文件分片上传地址获取错误')return}let chunkList = []fileChunks.map((chunkItem, index) => {chunkList.push({chunkNumber: index + 1,chunk: chunkItem,uploadUrl: uploadUrls[index],progress: 0,status: '—'})})//上传分片uploadChunkBase(chunkList, file.type).then(resp => {console.log('分片上传完成')let par = {fileName: file.name,uploadId: state.uploadId}//请求后端合并分片mergePart(par).then(resp => {ElMessage.info('上传成功,访问地址:' + resp.data)})})})
}/*** 文件分片*/
const createFileChunk = (file, size = chunkSize) => {const fileChunkList = []let count = 0while (count < file.size) {fileChunkList.push({file: file.slice(count, count + size)})count += size}return fileChunkList
}
//分片上传
const uploadChunkBase = (chunkList, contentType = 'application/octet-stream') => {let successCount = 0let totalChunks = chunkList.lengthreturn new Promise<void>((resolve, reject) => {const handler = () => {if (chunkList.length) {const chunkItem = chunkList.shift()// 直接上传二进制,不需要构造 FormData,否则上传后文件损坏service.put(chunkItem.uploadUrl, chunkItem.chunk.file, {headers: {'Content-Type': contentType}}).then(response => {if (response.status === 200) {console.log('分片:' + chunkItem.chunkNumber + ' 上传成功')successCount++// 继续上传下一个分片handler()} else {// 注意:这里没有针对失败做处理,请根据自己需求修改console.log('上传失败:' + response.status + ',' + response.statusText)}}).catch(error => {// 更新状态console.log('分片:' + chunkItem.chunkNumber + ' 上传失败,' + error)// 重新添加到队列中chunkList.push(chunkItem)handler()})}if (successCount >= totalChunks) {resolve()}}// 支持10个并发for (let i = 0; i < 10; i++) {handler()}})
}
utils/request
是对axios的封装,比如超时,返回体错误码判断等等
对应的 api/file.ts
import service from '@/utils/request'/** MD5校验 */
export const checkMd5 = (params?: object) => {return service.get('/oss/check', { params: params })
}/** 获取分片上传地址 */
export const getPartUrl = (params?: object) => {return service.get('/oss/part-url', { params: params })
}/** 分片合并 */
export const mergePart = (params?: object) => {return service.get('/oss/merge-part', { params: params, timeout: 10000 })
}
至此,分片上传即可使用
断点续传
这个其实就是在分片上传的基础做一个改进,将上传完成的分片反馈给后端做记录,再次续传时,只传对应的未上传分片即可,上传完成,再请求后端合并。
相关文章:
minio spring boot 秒传、分片上传、断点续传文件实现
此处后端使用的是前期封装的自定义starter,具体链接可参考:minio对象存储spring boot starter封装组件 这里主要针对前期封装的组件,做一个简单的应用,前端直传可查看之前的文章 秒传 秒传的逻辑比较简单,在前传上传…...

MTK平台使用Omnipeek分析空口协议讲解
讲解这个之前,我们先来了解下beacon/robe Request/Probe Response 三种帧 beacon帧 信标帧,由AP以一定的时间间隔周期性发出,以此来告诉外界自己无线网络的存在。 Beacon帧作为802.11中一个周期性的帧,Beacon周期调高,对应睡眠周期拉长,故节能(即越来休息100ms再起来…...

string和自动推断类型
欢迎来观看温柔了岁月.c的博客目前设有C学习专栏C语言项目专栏数据结构与算法专栏目前主要更新C学习专栏,C语言项目专栏不定时更新待C专栏完毕,会陆续更新C项目专栏和数据结构与算法专栏一周主要三更,星期三,星期五,星…...

【软件测试】从功能到自动化测试,测试人的进阶之路细节,这些必不可少......
目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 测试流程࿰…...

C语言青蛙跳台阶【图文详解】
青蛙跳台阶前言1. 题目介绍2. 解题思路3. 利用图片来演示青蛙跳台阶的原理4. 如何用C语言实现青蛙跳台阶前言 在本文,我们要与一只活泼可爱的小青蛙合作,带领着它跳上台阶,这个小家伙精力充沛,特别擅长于跳跃。我们要让它做我们的…...
笔记(五)——list容器的基础理论知识
list容器是一个双向链表容器,可以高效地进行插入删除元素,但是不能随机存取元素(不支持at()和[]操作符)。一、list容器的对象构造方法list对象采用模板类的默认构造形式例如list<T> lst;#include<iostream>…...
浅谈网络中接口幂等性设计问题
所谓幂等性设计,就是说,一次和多次请求某一个资源应该具有同样的副作用。用数学的语言来表达就是:f(x) f(f(x))。 在数学里,幂等有两种主要的定义。 在某二元运算下,幂等元素是指被自己重复运算(或对于函数…...

《C Primer Plus》第13章复习题与编程练习
《C Primer Plus》第13章复习题与编程练习复习题1. 下面的程序有什么问题?2. 下面的程序完成什么任务?(假设在命令行环境中运行)3. 假设程序中有下列语句:4. 编写一个程序,不接受任何命令行参数或接受一个命…...

计算机SCI论文应该怎么作图? - 易智编译EaseEditing
计算机SCI论文,作图时要注意以下几个方面的问题: 1.图片的格式要tiff或者eps; 2.文件大小不能超过10M; 3.长和宽也给出了具体要求; 4.色彩模式要RGB或者灰度图; 5.文中的文字字体和大小; …...

【一】kubernetes集群部署
一、docker环境搭建 1、移除以前docker相关包 sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine2、配置yam源 sudo yum install -y yum-utilssudo yum-config-manager --ad…...
Docker安装Redis
一、拉取镜像 命令::docker pull <镜像名称>:<版本号> docker pull redis 二:Docker挂载配置文件 挂载:即将宿主的文件和容器内部目录相关联,相互绑定,在宿主机内修改文件的话也随之修改容…...
在shell中执行一条可执行程序(./a.out) 系统执行的过程
目录 系统调度过程 用户空间角度: 内核角度 1、调用fork创建一个新进程 2、使用_fo_fork创建新进程 3、父进程调用wake_up_new_task尝试唤醒新进程 4、CPU选择一个合适的进程来运行; 5、运行新进程 6、实现负载均衡 系统调度过程 分析在命令行…...

【ArcGIS Pro二次开发】(10):属性表字段(field)的修改
在ArcGIS Pro中,经常会遇到用字段计算器对要素的属性表进行计算。下面以一个例子演示如何在ArcGIS Pro SDK二次开发中实现。 一、要实现的功能 如上图所示的要素图层,要实现如下功能: 当字段【市级行政区】的值为【泉州市】时,将…...
数据结构与算法—散列表
目录 散列表 散列函数 散列冲突解决 1、开放寻址法 1.1 线性探测 1.2 二次探测 1.3 双重散列 2、链表法 使用场景 单词查找 散列表与链表的结合使用LRU 散列表总结 散列表实例 散列表 Word 单词拼写功能,如何实现的?散列表(Has…...

计算机网络笔记、面试八股(一)—— TCP/IP网络模型
本章目录1. TCP/IP网络模型1.1 应用层1.1.1 应用层作用1.1.2 应用层有哪些常用协议1.2 运输层1.2.1 TCP与UDP的区别1.2.2 分块传输1.2.3 端口1.3 网络层1.3.1 IP报文1.3.2 IP地址1.3.3 网络号和主机号的获得1.3.4 子网掩码的获得1.3.5 路由1.3.6 IP地址与MAC地址的区别1.3.7 AR…...
Servlet笔记(18):国际化
三个概念 国际化: 意义着一个网站提供不同版本的翻译成访问者的语言或国籍的内容。本地化: 意味着向网站添加资源,以使其适应特定的地理或文化区域。区域设置: 针对某个国家的某个地区的设置。 Servlet可以根据请求者的区域设置…...

kibana搭建(windowslinux)
1.说明 搭建kibana方便查询es库,本文分别对windows和linux版本进行安装,因为es集群版本是7.4.1,所以配套的kibana也是选择相同版本 2.下载 https://artifacts.elastic.co/downloads/kibana/kibana-7.4.1-windows-x86_64.zip https://artifact…...

(pytorch进阶之路)Informer
论文:Informer: Beyond Efficient Transformer for Long Sequence Time-Series Forecasting (AAAI’21 Best Paper) 看了一下以前的论文学习学习,我也是重应用吧,所以代码部分会比较多,理论部分就一笔带过吧 论文作者也很良心的…...

关键词聚类和凸现分析-实战1——亚急性甲状腺炎的
审稿人问题第8页第26行-请指出#是什么意思,并解释为什么亚急性甲状腺炎在这里被列为#8。我认为在搜索亚急性甲状腺炎相关文章时,关键词共现分析应该提供关键词共现的数据。这些结果的实际用途是什么?亚急性甲状腺炎是一种较为罕见但重要的甲状腺疾病&am…...
二叉树——二叉搜索树中的众数
二叉搜索树中的众数 链接 给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。 如果树中有不止一个众数,可以按 任意顺序 返回。 假定…...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...

解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...

Android写一个捕获全局异常的工具类
项目开发和实际运行过程中难免会遇到异常发生,系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler,它是Thread的子类(就是package java.lang;里线程的Thread)。本文将利用它将设备信息、报错信息以及错误的发生时间都…...