【分布式云储存】Springboot微服务接入MinIO实现文件服务

文章目录

    • 前言
    • 技术回顾
    • 准备工作
      • 申请accessKey\secretKey
      • 创建数据存储桶
      • 公共资源直接访问测试
    • 接入springboot实现文件服务
      • 依赖引入
      • 配置文件
      • MinIO配置
      • MinIO工具类
    • OkHttpSSLSocketClient兼容ssl
    • 静态资源预览解决方案
    • 资源上传预览测试
    • 测试结果

前言

上篇博客我们介绍了分布式云存储MinIO作业环境的搭建,以及分布式云储存MinIO在实际的文件服务中的优势。那么,今天我们就小试牛刀来将MinIO接入我们的微服务项目,实现一个分布式的文件服务器。

技术回顾

MinIO 提供高性能、与S3 兼容的对象存储系统,让你自己能够构建自己的私有云储存服务。
MinIO原生支持 Kubernetes,它可用于每个独立的公共云、每个 Kubernetes 发行版、私有云和边缘的对象存储套件。
MinIO是软件定义的,不需要购买其他任何硬件,在 GNU AGPL v3 下是 100% 开源的。

准备工作

申请accessKey\secretKey

MinIO控制台申请accessKey\secretKey
http://your_hostname:18001~18004/login minio/minio123
在这里插入图片描述

创建数据存储桶

创建数据存储桶
在这里插入图片描述在这里插入图片描述

点击创建的桶我们进行访问策略配置
在这里插入图片描述
在这里插入图片描述

访问策略有private\custom\public
public 公共的桶,任何人都可以访问资源,直接映射为静态资源,可直接提供预览和下载
custom 自定义桶,用户根据自身需求定义访问规则
private 私有的桶,需要授权才能访问

根据一般的生产需求,我们定义一个private,一个custom桶。private保存私有资源,custom保存公共资源并禁止目录访问。
在这里插入图片描述

private 规则:
在这里插入图片描述

custom 规则:
在这里插入图片描述

{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Principal": {"AWS": ["*"]},"Action": ["s3:GetBucketLocation","s3:ListBucketMultipartUploads"],"Resource": ["arn:aws:s3:::sacpublic"]},{"Effect": "Allow","Principal": {"AWS": ["*"]},"Action": ["s3:AbortMultipartUpload","s3:DeleteObject","s3:GetObject","s3:ListMultipartUploadParts","s3:PutObject"],"Resource": ["arn:aws:s3:::sacpublic/*"]}]
}

公共资源直接访问测试

私有资源代码博文最后测试
公共资源直接访问测试:
在这里插入图片描述
在这里插入图片描述

接入springboot实现文件服务

依赖引入

maven引入依赖

<!--minio-->
<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.2.0</version>
</dependency>
<!--minio-->

配置文件

配置文件

minio.url = https://10.10.22.91:9100
minio.accessKey = fUIXbkBZ9UQTHOOZXNGW
minio.secretKey = sy1RAgItAOk9pk1gE7FbrPYzsZI87CfpGkuoY0KW
minio.buckets.public = sacpublic
minio.buckets.private = sacprivate

注意:接口调用minio url 为nginx映射出来的9000端口
http://your_hostname:9000

MinIO配置

MinIO配置

/*** MinioConfig* @author senfel* @version 1.0* @date 2023/9/14 11:37*/
@Configuration
@ConditionalOnProperty(name = "oss.file.service", havingValue = "minio", matchIfMissing = true)
public class MinioConfig {@Value("${minio.url}")private String minioUrl;@Value("${minio.accessKey}")private String accessKey;@Value("${minio.secretKey}")private String secretKey;@Beanpublic MinioClient getMinioClient() {return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();}}

MinIO工具类

MinIO工具类

/*** MinioUtil* @author senfel* @version 1.0* @date 2023/9/14 10:26*/
@Component
@ConditionalOnProperty(name = "oss.file.service", havingValue = "minio", matchIfMissing = true)
public class MinioUtil {@Resourceprivate MinioClient minioClient;/*** 创建一个桶*/public void createBucket(String bucket) throws Exception {boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());if (!found) {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());}}/*** 上传一个文件*/public ObjectWriteResponse uploadFile(InputStream stream, String bucket, String objectName) throws Exception {String prefix = objectName.substring(objectName.lastIndexOf(".") + 1);//静态资源预览解决方案//String contentType = ViewContentType.getContentType(prefix);ObjectWriteResponse objectWriteResponse = minioClient.putObject(PutObjectArgs.builder().bucket(bucket).object(objectName).contentType(contentType).stream(stream, -1, 10485760).build());return objectWriteResponse;}/*** 列出所有的桶*/public List<String> listBuckets() throws Exception {List<Bucket> list = minioClient.listBuckets();List<String> names = new ArrayList<>();list.forEach(b -> {names.add(b.name());});return names;}/*** 下载一个文件*/public InputStream download(String bucket, String objectName) throws Exception {InputStream stream = minioClient.getObject(GetObjectArgs.builder().bucket(bucket).object(objectName).build());return stream;}/*** 删除一个桶*/public void deleteBucket(String bucket) throws Exception {minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucket).build());}/*** 删除一个对象*/public void deleteObject(String bucket, String objectName) throws Exception {minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucket).object(objectName).build());}/*** 复制文件** @Param: [sourceBucket, sourceObject, targetBucket, targetObject]* @return: void* @Date: 2021/11/15*/public void copyObject(String sourceBucket, String sourceObject, String targetBucket, String targetObject) throws Exception {this.createBucket(targetBucket);minioClient.copyObject(CopyObjectArgs.builder().bucket(targetBucket).object(targetObject).source(CopySource.builder().bucket(sourceBucket).object(sourceObject).build()).build());}/*** 获取文件信息** @Param: [bucket, objectName]* @return: java.lang.String*/public String getObjectInfo(String bucket, String objectName) throws Exception {return minioClient.statObject(StatObjectArgs.builder().bucket(bucket).object(objectName).build()).toString();}/*** 生成一个给HTTP GET请求用的presigned URL。浏览器/移动端的客户端可以用这个URL进行下载,即使其所在的存储桶是私有的。* @Param: [bucketName, objectName, expires]* @return: java.lang.String*/public String getPresignedObjectUrl(String bucketName, String objectName, Integer expires) throws Exception {GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(objectName).expiry(expires).method(Method.GET).build();return minioClient.getPresignedObjectUrl(build);}}

OkHttpSSLSocketClient兼容ssl

对于改解决方案一般生产环境都有固定的域名和匹配的ssl证书,如果也不用https我们代码则不用兼容ssl。但是如果我们配置了不可信任的ssl,这里我们则需要进行ssl兼容方案。

/*** MinioConfig* @author senfel* @version 1.0* @date 2023/9/14 11:37*/
@Configuration
@ConditionalOnProperty(name = "oss.file.service", havingValue = "minio", matchIfMissing = true)
public class MinioConfig {@Value("${minio.url}")private String minioUrl;@Value("${minio.accessKey}")private String accessKey;@Value("${minio.secretKey}")private String secretKey;@Beanpublic MinioClient getMinioClient() {OkHttpClient okHttpClient = new OkHttpClient.Builder().sslSocketFactory(OkHttpSSLSocketClient.getSSLSocketFactory(),OkHttpSSLSocketClient.getX509TrustManager()) // //通过sslSocketFactory方法设置https证书.hostnameVerifier(OkHttpSSLSocketClient.getHostnameVerifier()).build();return MinioClient.builder().endpoint(minioUrl).httpClient(okHttpClient).credentials(accessKey, secretKey).build();}}
/*** OkHttpSSLSocketClient* @author senfel* @version 1.0* @date 2023/9/15 10:07*/
public class OkHttpSSLSocketClient{//获取SSLSocketFactorypublic static SSLSocketFactory getSSLSocketFactory() {try {SSLContext sslContext = SSLContext.getInstance("SSL");sslContext.init(null, getTrustManager(), new SecureRandom());return sslContext.getSocketFactory();} catch (Exception e) {throw new RuntimeException(e);}}//获取TrustManagerprivate static TrustManager[] getTrustManager() {TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {@Overridepublic void checkClientTrusted(X509Certificate[] chain, String authType) {}@Overridepublic void checkServerTrusted(X509Certificate[] chain, String authType) {}@Overridepublic X509Certificate[] getAcceptedIssuers() {return new X509Certificate[]{};}}};return trustAllCerts;}//获取HostnameVerifier,验证主机名public static HostnameVerifier getHostnameVerifier() {HostnameVerifier hostnameVerifier = (s, sslSession) -> true;return hostnameVerifier;}//X509TrustManager:证书信任器管理类public static X509TrustManager getX509TrustManager() {X509TrustManager x509TrustManager = new X509TrustManager() {//检查客户端的证书是否可信@Overridepublic void checkClientTrusted(X509Certificate[] chain, String authType) {}//检查服务器端的证书是否可信@Overridepublic void checkServerTrusted(X509Certificate[] chain, String authType) {}@Overridepublic X509Certificate[] getAcceptedIssuers() {return new X509Certificate[0];}};return x509TrustManager;}
}

静态资源预览解决方案

由于我们使用API上传,minio不能区分我们资源的类型,如果资源类型不对则不能正确提供预览功能,都直接变成为访问资源链接就下载了。

所以,在实际的项目集成中我们在上传资源前需要将资源类型写入请求中,方便minio解析并提供预览和下载功能。

/*** 上传一个文件*/
public ObjectWriteResponse uploadFile(InputStream stream, String bucket, String objectName) throws Exception {String prefix = objectName.substring(objectName.lastIndexOf(".") + 1);//静态资源预览解决方案String contentType = ViewContentType.getContentType(prefix);ObjectWriteResponse objectWriteResponse = minioClient.putObject(PutObjectArgs.builder().bucket(bucket).object(objectName).contentType(contentType).stream(stream, -1, 10485760).build());return objectWriteResponse;
}
/*** ViewContentType* @author senfel* @version 1.0* @date 2023/9/14 17:27*/
public enum ViewContentType {DEFAULT("default","application/octet-stream"),JPG("jpg", "image/jpeg"),TIFF("tiff", "image/tiff"),GIF("gif", "image/gif"),JFIF("jfif", "image/jpeg"),PNG("png", "image/png"),TIF("tif", "image/tiff"),ICO("ico", "image/x-icon"),JPEG("jpeg", "image/jpeg"),WBMP("wbmp", "image/vnd.wap.wbmp"),FAX("fax", "image/fax"),NET("net", "image/pnetvue"),JPE("jpe", "image/jpeg"),RP("rp", "image/vnd.rn-realpix");private String prefix;private String type;public static String getContentType(String prefix){if(StringUtils.isEmpty(prefix)){return DEFAULT.getType();}prefix = prefix.substring(prefix.lastIndexOf(".") + 1);for (ViewContentType value : ViewContentType.values()) {if(prefix.equalsIgnoreCase(value.getPrefix())){return value.getType();}}return DEFAULT.getType();}ViewContentType(String prefix, String type) {this.prefix = prefix;this.type = type;}public String getPrefix() {return prefix;}public String getType() {return type;}
}

资源上传预览测试

MinIO对于图片等资源可以直接预览,对于excel文档等直接提供下载功能

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class CodeDbInfoServiceTests  {@Resource@Lazyprivate MinioUtil minioUtil;/*** upload* @author senfel* @date 2023/9/27 10:00* @return void*/@Testpublic void upload() throws Exception {FileInputStream fileInputStream = new FileInputStream("C:/Users/dev/Desktop/minio.png");ObjectWriteResponse sacprivate = minioUtil.uploadFile(fileInputStream, "sacprivate", "test/minio.png");System.err.println(sacprivate.bucket());}/*** 获取私库连接* @author senfel* @date 2023/9/27 10:01* @return void*/@Testpublic void getPrivateUrl() throws Exception{String url = minioUtil.getPresignedObjectUrl("sacprivate", "test/minio.png", 60);System.err.println(url);}
}

测试结果

图片成功上传
在这里插入图片描述

私库直接预览访问失败
在这里插入图片描述

获取私库链接过期时间为60s
在这里插入图片描述

访问成功
在这里插入图片描述

60s后再次访问该链接,提示链接已经过期
在这里插入图片描述

至此minio接入并测试完成,对于公开桶的资源直接可任意访问不用获取有效期链接。

写在最后
Springboot微服务接入MinIO实现文件服务较为简单,我们只要按照官方文档引入依赖调用即可。值得注意的是我们根据需求选择接入ssl兼容方案和静态资源预览功能。当然,minio的private\custom\public可以完全实现我们各种需求,可以完全替代市场上付费和笨重的分布式服务。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

day06_循环

今日内容 零、 复习昨日 一、循环 二、流程控制关键词 零、 复习昨日 8个基本数据类型 变量的使用步骤 1)声明2)赋值3)使用 声明,数据类型 变量名 不一定非得是基本类型 int a; String s; Scanner scanner;赋值,只要符合类型(能默认转换)就能赋值 int a 1; double d 1; Scann…

【KingbaseES】银河麒麟V10 ARM64架构_安装人大金仓数据库KingbaseES_V8R6(CentOS8)

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,Java基础学习,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的…

基于Java的毕业设计管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

云部署家里的服务器

1.固定静态ip 查看ip地址&#xff0c;en开头的 ifconfig查看路由器ip&#xff0c;via开头的 ip route修改配置文件 cd /etc/netplan/ #来到这个文件夹 sudo cp 01-network-manager-all.yaml 01-network-manager-all.yaml.bak #先备…

excel筛选后求和

需要对excel先筛选&#xff0c;后对“完成数量”进行求和。初始表格如下&#xff1a; 一、选中表内任意单元格&#xff0c;按ctrlshiftL&#xff0c;开启筛选 二、根据“部门”筛选&#xff0c;比如选择“一班” 筛选完毕后&#xff0c;选中上图单元格&#xff0c;然后按alt后&…

泰国数字加密平台Bitkub创始人到访和数集团:以数字化创新探索科技前沿密码

9月21日&#xff0c;泰国数字加密货币交易平台Bitkub创始人兼首席执行官&#xff08;CEO&#xff09;Jirayut Srupsrisopa (Topp)先生到访上海和数集团&#xff0c;在和数集团董事长唐毅陪同下实地参观了和数集团上海总部&#xff0c;听取了和数集团在引领前沿数字化创新&#…

【跟小嘉学习区块链】二、Hyperledger Fabric 架构详解

系列文章目录 【跟小嘉学习区块链】一、区块链基础知识与关键技术解析 【跟小嘉学习区块链】二、区块链基础知识与关键技术解析 文章目录 系列文章目录[TOC](文章目录) 前言一、Hyperledger 社区1.1、Hyperledger(面向企业的分布式账本)1.2、Hyperledger社区组织结构 二、Hype…

结构型设计模式——组合模式

摘要 组合模式(composite pattern): 允许你将对象组合成树形结构来表现"整体/部分"层次结构. 组合能让客户以一致的方式处理个别对象以及对象组合。 一、组合模式的意图 将对象组合成树形结构来表示“整体/部分”层次关系&#xff0c;允许用户以相同的方式处理单独…

性能测试工具 — JMeter

一、JMeter准备工作 1、JMeter介绍 Apache JMeter 应用程序是开源软件&#xff0c;是一个 100% 纯 Java 应用程序。用于测试Web应用程序、API和其他网络协议的性能。它具有以下特点&#xff1a; 1. 开源免费&#xff1a;JMeter是Apache软件基金会下的一个开源项目&#xff0…

〔025〕Stable Diffusion 之 接口开发 篇

✨ 目录 🎈 启动接口🎈 接口文档🎈 接口开发🎈 代码解释🎈 启动接口 想要在各种其他服务中对接 Stable Diffusion 的绘画功能,需要开启 Stable Diffusion 的 api 功能开发接口需要有一定的技术功底才可以,非技术人员其实不用学习直接在 webui-user.bat 文件中的 se…

【Flink】

事件驱动型应用 核心目标&#xff1a;数据流上的有状态计算 Apache Flink是一个框架和分布式处理引擎&#xff0c;用于对无界或有界数据流进行有状态计算。 运行逻辑 状态 把流处理需要的额外数据保存成一个“状态”,然后针对这条数据进行处理,并且更新状态。这就是所谓的“…

电脑突然提示mfc140u.dll丢失,缺失mfc140u.dll无法运行程序的解决方法

在当今信息化社会&#xff0c;电脑已经成为我们生活和工作中不可或缺的一部分。然而&#xff0c;随着技术的不断发展&#xff0c;电脑也会出现各种问题。其中&#xff0c;最常见的问题之一就是“mfc140u.dll丢失”。那么&#xff0c;当我们遇到这个问题时&#xff0c;应该如何解…

redis部署与管理

目录 一、关系数据库与非关系型数据库&#xff1a; 1. 关系型数据库&#xff1a; 2.非关系型数据库&#xff1a; 二、关系型数据库和非关系型数据库区别&#xff1a; &#xff08;1&#xff09;数据存储方式不同&#xff1a; &#xff08;2&#xff09;扩展方式不同&#xf…

华为云云耀云服务器L实例评测|华为云云耀云服务器L实例CentOS的存储和备份策略

1 华为云云耀云服务器L实例介绍 华为云云耀云服务器L实例是华为云计算服务中的一种虚拟云服务器&#xff0c;它提供了强大的计算资源&#xff0c;可以在云端运行各种应用程序和服务。 华为云服务器提供了多种实例类型&#xff0c;包括通用型、计算优化型、内存优化型等&#…

【数据库】形式化关系查询语言(一):关系代数Relational Algebra

目录 一、关系代数Relational Algebra 1. 基本运算 a. 选择运算&#xff08;Select Operation&#xff09; b. 投影运算&#xff08;Project Operation&#xff09; 组合 c. 并运算&#xff08;Union Operation&#xff09; d. 集合差运算&#xff08;Set Difference Op…

STM32F4X UCOSIII任务消息队列

STM32F4X UCOSIII任务消息队列 任务消息队列和内核消息队列对比内核消息队列内核消息队列 UCOSIII任务消息队列API任务消息队列发送函数任务消息队列接收函数 UCOSIII任务消息队列例程 之前的章节中讲解过消息队列这个机制&#xff0c;UCOSIII除了有内核消息队列之外&#xff0…

开学教师自我介绍模版:打造个人品牌,轻松赢得学生喜爱

这里有一篇2000字左右的教师自我介绍长文&#xff1a; 亲爱的同学们&#xff0c;我是你们的XX老师。开学第一天&#xff0c;我非常高兴能在这里与大家见面。作为一名教师&#xff0c;我的职责是把知识教给你们&#xff0c;指导你们成长。同时&#xff0c;我也希望通过这次自我…

【JUC】一文弄懂@Async的使用与原理

文章目录 1. Async异步任务概述2. 深入Async的底层2.1 Async注解2.2 EnableAsync注解2.3 默认线程池 1. Async异步任务概述 在Spring3.X的版本之后&#xff0c;内置了Async解决了多个任务同步进行导致接口响应迟缓的情况。 使用Async注解可以异步执行一个任务&#xff0c;这个…

Docker清理

title: “Mysql安装” createTime: 2022-01-04T20:07:3108:00 updateTime: 2022-01-04T20:07:3108:00 draft: false author: “name” tags: [“mysql”] categories: [“docker”] description: “测试的” docker-mysql安装部署文档 文章目录 title: "Mysql安装" …

玩转gpgpu-sim 04记—— __cudaRegisterBinary() of gpgpu-sim 到底做了什么

官方文档&#xff1a; GPGPU-Sim 3.x Manual __cudaRegisterBinary(void*) 被执行到的代码逻辑如下&#xff1a; void** CUDARTAPI __cudaRegisterFatBinary( void *fatCubin ) { #if (CUDART_VERSION < 2010)printf("GPGPU-Sim PTX: ERROR ** this version of GPGPU…