SpringBoot + minio实现分片上传、秒传、续传
什么是minio
MinIO是一个基于Go实现的高性能、兼容S3协议的对象存储。它采用GNU AGPL v3开源协议,项目地址是https://github.com/minio/minio。
引用官网:
MinIO是根据GNU Affero通用公共许可证v3.0发布的高性能对象存储。它与Amazon S3云存储服务兼容。使用MinIO构建用于机器学习,分析和应用程序数据工作负载的高性能基础架构。
官网地址:
https://min.io/
文档地址:
https://docs.min.io/
一. 使用docker 搭建minio 服务
GNU / Linux和macOS
docker run -p 9000:9000 \ --name minio1 \ -v /mnt/data:/data \ -e "MINIO_ROOT_USER=AKIAIOSFODNN7EXAMPLE" \ -e "MINIO_ROOT_PASSWORD=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \ minio/minio server /data
windows
docker run -p 9000:9000 \ --name minio1 \ -v D:\data:/data \ -e "MINIO_ROOT_USER=AKIAIOSFODNN7EXAMPLE" \ -e "MINIO_ROOT_PASSWORD=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \ minio/minio server /data
-
MINIO_ROOT_USER
:为用户key -
MINIO_ROOT_PASSWORD
:为用户密钥
以上搭建的都是单机版的。想要了解分布式 的方式请查看官网文档。
这就是在win的docker上运行的。
更多开源项目:https://www.yoodb.com/projects/springboot-user-manger.html
当启动后在浏览器访问http://localhost:9000
就可以访问minio的图形化界面了,如图所示:
二. 下面开始搭建springboot 环境
初始化一个springboot项目大家都会,这里不多做介绍。
主要是介绍需要引入的依赖:
<!-- thymeleaf模板渲染引擎--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency><!-- 操作minio的java客户端--> <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>8.2.1</version> </dependency><!-- lombok插件--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
依赖可以官方文档里找:https://docs.min.io/docs/java-client-quickstart-guide.html
下面介绍配置文件:
spring: servlet: multipart: max-file-size: 10MB max-request-size: 10MB *#minio配置* minio: access-key: AKIAIOSFODNN7EXAMPLE *#key就是docker初始化是设置的,密钥相同* secret-key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY url: http://localhost:9000 bucket-name: wdhcr thymeleaf: cache: false
创建minio的配置类:
`@Configuration
@ConfigurationProperties(prefix = “spring.minio”)
@Data
public class MinioConfiguration {
private String accessKey;
private String secretKey;
private String url;
private String bucketName;
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(url)
.credentials(accessKey, secretKey)
.build();
}
}
`
使用配置属性绑定进行参数绑定,并初始化一个minio client对象放入容器中。
下面就是我封装的minio client 操作minio的简单方法的组件。
`@Component
public class MinioComp {
@Autowired
private MinioClient minioClient;
@Autowired
private MinioConfiguration configuration;
/**
* @description: 获取上传临时签名,公众 号Java精选
* @dateTime: 2021/5/13 14:12
*/
public Map getPolicy(String fileName, ZonedDateTime time) {
PostPolicy postPolicy = new PostPolicy(configuration.getBucketName(), time);
postPolicy.addEqualsCondition(“key”, fileName);
try {
Map<String, String> map = minioClient.getPresignedPostFormData(postPolicy);
HashMap<String, String> map1 = new HashMap<>();
map.forEach((k,v)->{
map1.put(k.replaceAll(“-”,“”),v);
});
map1.put(“host”,configuration.getUrl()+“/”+configuration.getBucketName());
return map1;
} catch (ErrorResponseException e) {
e.printStackTrace();
} catch (InsufficientDataException e) {
e.printStackTrace();
} catch (InternalException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidResponseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (ServerException e) {
e.printStackTrace();
} catch (XmlParserException e) {
e.printStackTrace();
}
return null;
}
/**
* @description: 获取上传文件的url,公众 号Java精选,有惊喜!
* @dateTime: 2021/5/13 14:15
*/
public String getPolicyUrl(String objectName, Method method, int time, TimeUnit timeUnit) {
try {
return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
.method(method)
.bucket(configuration.getBucketName())
.object(objectName)
.expiry(time, timeUnit).build());
} catch (ErrorResponseException e) {
e.printStackTrace();
} catch (InsufficientDataException e) {
e.printStackTrace();
} catch (InternalException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidResponseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (XmlParserException e) {
e.printStackTrace();
} catch (ServerException e) {
e.printStackTrace();
}
return null;
}
/**
* @description: 上传文件
* @dateTime: 2021/5/13 14:17
/
public void upload(MultipartFile file, String fileName) {
// 使用putObject上传一个文件到存储桶中。
try {
InputStream inputStream = file.getInputStream();
minioClient.putObject(PutObjectArgs.builder()
.bucket(configuration.getBucketName())
.object(fileName)
.stream(inputStream, file.getSize(), -1)
.contentType(file.getContentType())
.build());
} catch (ErrorResponseException e) {
e.printStackTrace();
} catch (InsufficientDataException e) {
e.printStackTrace();
} catch (InternalException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidResponseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (ServerException e) {
e.printStackTrace();
} catch (XmlParserException e) {
e.printStackTrace();
}
}
/*
* @description: 根据filename获取文件访问地址
* @dateTime: 2021/5/17 11:28
*/
public String getUrl(String objectName, int time, TimeUnit timeUnit) {
String url = null;
try {
url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(configuration.getBucketName())
.object(objectName)
.expiry(time, timeUnit).build());
} catch (ErrorResponseException e) {
e.printStackTrace();
} catch (InsufficientDataException e) {
e.printStackTrace();
} catch (InternalException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidResponseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (XmlParserException e) {
e.printStackTrace();
} catch (ServerException e) {
e.printStackTrace();
}
return url;
}
}
`
简单说明:
-
使用MultipartFile接收前端文件流,再上传到minio。
-
构建一个formData的签名数据,给前端,让前端之前上传到minio。
-
构建一个可以上传的临时URL给前端,前端通过携带文件请求该URL进行上传。
-
使用filename请求服务端获取临时访问文件的URL。(最长时间为7 天,想要永久性访问,需要其他设置,这里不做说明。)
-
推荐,公众 号Java精选,回复java面试,获取面试资料,支持在线刷题。
下面展示页面html,使用的是VUE+element-ui进行渲染。
`
传统上传
前端formData直传
前端Url直传
uploadHandle(options) {
let {file} = options;
this.traditionPost(file);
},
traditionPost(file) {
_that = this
const form = new FormData();
form.append(“fileName”, file.name);
form.append(“file”, file);
this.axiosPost(“post”, “/upload”, form).then(function (res) {
if (res.status === 200) {
_that.imgUrl = res.data.data
} else {
alert(“上传失败!”)
}
})
},
getpolicy(file) {
_that = this
axios.get(‘policy?fileName=’ + file.name)
.then(function (response) {
let {xamzalgorithm, xamzcredential, policy, xamzsignature, xamzdate, host} = response.data.data;
let formData = new FormData();
formData.append(“key”, file.name);
formData.append(“x-amz-algorithm”, xamzalgorithm); // 让服务端返回200,不设置则默认返回204。
formData.append(“x-amz-credential”, xamzcredential);
formData.append(“policy”, policy);
formData.append(“x-amz-signature”, xamzsignature);
formData.append(“x-amz-date”, xamzdate);
formData.append(“file”, file);
// 发送 POST 请求
_that.axiosPost(“post”, host, formData).then(function (res) {
if (res.status === 204) {
axios.get(‘url?fileName=’ + file.name).then(function (res) {
_that.directUrl = res.data.data;
})
} else {
alert(“上传失败!”)
}
})
})
},
httpRequestHandle(options) {
let {file} = options;
this.getpolicy(file);
},
UrlUploadHandle(options) {
let {file} = options;
this.getUploadUrl(file);
},
getUploadUrl(file) {
_that = this
console.log(file)
axios.get(‘uploadUrl?fileName=’ + file.name)
.then(function (response) {
let url = response.data.data;
// 发送 put 请求
let config = {‘Content-Type’: file.type}
_that.axiosPost(“put”, url, file, config).then(function (res) {
if (res.status === 200) {
axios.get(‘url?fileName=’ + file.name).then(function (res) {
_that.uploadUrl = res.data.data;
})
} else {
alert(“上传失败!”)
}
})
})
},
//封装
//axios封装post请求
axiosPost(method, url, data, config) {
let result = axios({
method: method,
url: url,
data: data,
headers: config
}).then(resp => {
return resp
}).catch(error => {
return “exception=” + error;
});
return result;
}
}
})
页面的效果就如上图所示。
可以分别体验不同的实现效果。
以上就是使用springboot搭建基于minio的高性能存储服务的全部步骤了。
本项目地址:
https://gitee.com/jack_whh/minio-upload
作者:HUWD
https://blog.csdn.net/weixin_45089791/article/details/116921075/
相关文章:

SpringBoot + minio实现分片上传、秒传、续传
什么是minio MinIO是一个基于Go实现的高性能、兼容S3协议的对象存储。它采用GNU AGPL v3开源协议,项目地址是https://github.com/minio/minio。 引用官网: MinIO是根据GNU Affero通用公共许可证v3.0发布的高性能对象存储。它与Amazon S3云存储服务兼容…...
logback 里面设置 自动删除3天之前的日志
目录 1 实现 1 实现 要实现达到一定大小后将日志文件压缩,并删除三天前的日志数据,可以结合使用 SizeAndTimeBasedRollingPolicy 滚动策略和 DeleteOlderThan 选项来配置。下面是一个示例配置,实现日志文件达到一定大小后进行滚动和压缩&…...

对于数据库查询索引和查字典索引的理解
之前面试问过我对于数据库索引的理解,这个问题不是具体的问题太宽泛,面试官也没进行引导,我不知道怎么回答,下面是结合查字典进行理解。 查字典 拿查字典举例,知道一个字怎么写但是不知道具体的意思以及发音ÿ…...

git删除已经提交的大文件
当你不小心把一个巨大的二进制文件提交到git仓库的时候,此时删除再提交也没有用了,大文件已经在仓库中留底了。另外比如需要删除某个需要保密的文件,都是相同的解决办法。 我本来想着把dll放在三方库里面提交到仓库里,省得在不同…...
【数据分析】pandas 一
目录 一,pandas简介: 二,pandas数据结构Series简介: 2.1 data为ndarray 2.2 data为字典 三,Serise切片操作: 四,Series性质: 4.1 Series类似于numpy,字典 4.2 矢量化操作和标…...
题解 | #G.Gcd# 2023牛客暑期多校6
G.Gcd 数论 题目大意 给定一个包含两个非负数的初始集合 S { x , y } S\{x,y\} S{x,y} 每次操作可以选定其中不相等的两个数 a , b a,b a,b ,并将 a − b a-b a−b 或 g c d ( a , b ) gcd(a,b) gcd(a,b) 置入集合 S S S ,其中 g c d ( 0 , a …...

苍穹外卖day10——订单状态定时处理(Spring Task)、来单提醒和客户催单(WebSocket)
预期效果 对于超时没处理的需要定时程序处理。基于SpringTask实现。 来单提醒和客户催单。基于WebSocket实现。 Spring Task 介绍 Cron表达式 周几通常不能和日一起指定。 cron表达式在线生成器 在线Cron表达式生成器 入门案例 创建定时任务类 /*** 定义定时任务类*/ Slf4j…...

【多线程初阶】多线程案例之单例模式
文章目录 前言1. 什么是单例模式2. 饿汉模式3. 懒汉模式 --- 单线程版4. 懒汉模式 --- 多线程版5. 懒汉模式 --- 多线程改进版总结 前言 本文主要给大家讲解多线程的一个重要案例 — 单例模式. 关注收藏, 开始学习吧🧐 1. 什么是单例模式 单例模式是一种很经典的…...

跨境选品怎么选?建议独立站卖家收下这份利基产品查找攻略!
跨境电商平台现在可谓是火热发展中,独立站出海风口,其实选择的机会还真不少,相比国内电商的发展势头,看得出来,未来跨境电商的大门,对你而言,敞开着。选品这事儿,就像你上战场前挑选…...

[C++项目] Boost文档 站内搜索引擎(1): 项目背景介绍、相关技术栈、相关概念介绍...
项目背景 Boost库是C中一个非常重要的开源库. 它实现了许多C标准库中没有涉及的特性和功能, 一度成为了C标准库的拓展库. C新标准的内容, 很大一部分脱胎于Boost库中. Boost库的高质量代码 以及 提供了更多实用方便的C组件, 使得Boost库在C开发中会被高频使用 为方便开发者学…...

opencv-32 图像平滑处理-高斯滤波cv2.GaussianBlur()
在进行均值滤波和方框滤波时,其邻域内每个像素的权重是相等的。在高斯滤波中,会将中心点的权重值加大,远离中心点的权重值减小,在此基础上计算邻域内各个像素值不同权重 的和。 基本原理 在高斯滤波中,卷积核中的值不…...

Windows 环境Kubernetes安装
目录 前言 安装 Docker 安装 Kubernetes Windows 安装 kubectl 介绍 安装 开启 Kubernetes 前言 Docker作为当前最流行的容器化平台,为Kubernetes提供了强大的容器化技术基础。Kubernetes与Docker的结合,使得容器化应用程序在大规模集群中得以简…...

自建类ChatGPT服务:本地化部署与远程访问教程
🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…...

常用SQL语句总结
SQL语句 文章目录 SQL语句1 SQL语句简介2 DQL(数据查询语句)3 DML(数据操纵语句)4 DDL(数据定义语句)5 DCL(数据控制语句)6 TCL(事务控制语句) 1 SQL语句简介…...

arm交叉编译lmbench
一、下载lmbench www.bitmover.com/lmbench 官网下载,http://www.bitmover.com/lmbench/lmbench3.tar.gz 我没有下载下来,找的别人的百度云下载 链接: https://pan.baidu.com/s/1tGo1clCqY-jQPN8G1eWSsg 提取码: f6jd 二、修改makefile 修改三个文件…...

ExtJs 7.7.0 下载方法与去除trial水印
背景 最近发现Sencha ExtJs发布了ExtJs7.7.0版本,立刻下载了SDK包,许多朋友不知如何下载,如何去除右上角的trial水印。本文讲下相关下载技巧与方法。 下载SDK 首先需要申请试用,申请地址如下,需要注意可能需要梯子&…...
Android11开发规划
文章目录 规划总结规划 提示:这里可以添加本文要记录的大概内容: 从本文开始,会介绍如何移植瑞芯微提供的Android11源码到自己的RK3568的板子上 下面是整个Android开发的规划: 包括以下部分: … 一、移植部分 下载编译瑞芯微提供的源码 瑞芯微原厂源码目录介绍...

活动隔断在现在酒店运用的方式
活动隔断是一种在酒店内部划分空间的方式,用于实现不同活动的隔离和隐私。现代酒店常用的活动隔断方式有以下几种: 1. 固定隔断:使用墙体、固定屏风或者板材等材料,将空间划分为不同的房间或区域。这种方式常用于划分客房、会议室…...

Jenkins工具系列 —— 插件 钉钉发送消息
文章目录 安装插件 Ding TalkJenkins 配置钉钉机器人钉钉APP配置项目中启动钉钉通知功能 安装插件 Ding Talk 点击 左侧的 Manage Jenkins —> Plugins ——> 左侧的 Available plugins Jenkins 配置钉钉机器人 点击 左侧的 Manage Jenkins ,拉到最后 钉…...

LeetCode 26 题:删除有序数组的重复项
思路 在写这一个题时,我突然想到了Python中的 set()函数可能会有大用处,便选择了用Python写。 set()函数可以将列表转化为集合,集合会保证元素的单一性,所以会自动删去相同字符。 …...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...