【分布式云储存】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.rhkb.cn/news/147608.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UCOS的任务创建和删除

一、任务创建和删除的API函数 1、任务创建和删除本质就是调用uC/OS的函数 API函数 描述 OSTaskCreate() 创建任务 OSTaskDel() 删除任务 注意&#xff1a; 1&#xff0c;使用OSTaskCreate() 创建任务&#xff0c;任务的任务控制块以及任务栈空间所需的内存&#xff0c…

【云备份项目】:环境搭建(g++、json库、bundle库、httplib库)

文章目录 1. g 升级到 7.3 版本2. 安装 jsoncpp 库3. 下载 bundle 数据压缩库4. 下载 httplib 库从 Win 传输文件到 Linux解压缩 1. g 升级到 7.3 版本 &#x1f517;链接跳转 2. 安装 jsoncpp 库 &#x1f517;链接跳转 3. 下载 bundle 数据压缩库 安装 git 工具 sudo yum…

Linux性能优化--性能工具-系统CPU

2.0.概述 本章概述了系统级的Linux性能工具。这些工具是你追踪性能问题时的第一道防线。它们能展示整个系统的性能情况和哪些部分表现不好。 1.理解系统级性能的基本指标&#xff0c;包括CPU的使用情况。 2.明白哪些工具可以检索这些系统级性能指标。 2.1CPU性能统计信息 为…

北京开发APP需要多少钱

北京开发一个移动应用&#xff08;APP&#xff09;的费用因多种因素而异&#xff0c;包括项目的规模、复杂性、所需功能、设计要求、技术选择、开发团队的经验和地理位置等。一般来说&#xff0c;北京的APP开发费用通常较高&#xff0c;因为这是中国的主要技术和创新中心之一&a…

C++语言GDAL批量裁剪多波段栅格图像:基于像元个数裁剪

本文介绍基于C 语言的GDAL模块&#xff0c;按照给定的像元行数与列数&#xff0c;批量裁剪大量多波段栅格遥感影像文件&#xff0c;并将所得到的裁剪后新的多波段遥感影像文件保存在指定路径中的方法。 在之前的文章中&#xff0c;我们多次介绍了在不同平台&#xff0c;或基于不…

力扣 -- 322. 零钱兑换(完全背包问题)

参考代码&#xff1a; 未优化代码&#xff1a; class Solution { public:int coinChange(vector<int>& coins, int amount) {int n coins.size();const int INF 0x3f3f3f3f;//多开一行&#xff0c;多开一列vector<vector<int>> dp(n 1, vector<i…

ADB的概念、使用场景、工作原理

文章目录 一、adb概念&#xff1a;Android Debug Bridge&#xff0c;一个可以控制安卓设备的通用命令行工具二、adb的使用场景&#xff1a;操作手机设备、app 自动化测试1.传输文件2.兼容性测试&#xff08;手机墙&#xff09;3.云测平台4.测试框架底层封装&#xff1a;APP自动…

【生命周期】

生命周期 1 引出生命周期2 分析生命周期3 总结生命周期 1 引出生命周期 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta …

【Java 进阶篇】JDBC PreparedStatement 详解

在Java中&#xff0c;与关系型数据库进行交互是非常常见的任务之一。JDBC&#xff08;Java Database Connectivity&#xff09;是Java平台的一个标准API&#xff0c;用于连接和操作各种关系型数据库。其中&#xff0c;PreparedStatement 是 JDBC 中一个重要的接口&#xff0c;用…

跟着顶级科研报告IPCC学绘图:温度折线/柱图/条带/双y轴

复现IPCC气候变化过程图 引言 升温条带Warming stripes&#xff08;有时称为气候条带&#xff0c;目前尚无合适且统一的中文释义&#xff09;是数据可视化图形&#xff0c;使用一系列按时间顺序排列的彩色条纹来视觉化描绘长期温度趋势。 在IPCC报告中经常使用这一方案 IPCC是…

认识柔性数组

在C99中&#xff0c;结构中的最后一个元素允许是未知大小的数组&#xff0c;这就叫做柔性数组成员 限制条件是&#xff1a; 结构体中最后一个成员未知大小的数组 1.柔性数组的形式 那么我们怎样写一个柔性数组呢 typedef struct st_type {int i;int a[0];//柔性数组成员 }ty…

SpringBoot 可以同时处理多少请求

一、前言 首先&#xff0c;在Spring Boot应用中&#xff0c;我们可以使用 Tomcat、Jetty、Undertow 等嵌入式 Web 服务器作为应用程序的运行容器。这些服务器都支持并发请求处理的能力。另外&#xff0c;Spring Boot 还提供了一些配置参数&#xff0c;可以对 Web 服务器进行调…

互联网Java工程师面试题·MyBatis 篇·第二弹

目录 16、Xml 映射文件中&#xff0c;除了常见的 select|insert|updae|delete标签之外&#xff0c;还有哪些标签&#xff1f; 17、Mybatis 的 Xml 映射文件中&#xff0c;不同的 Xml 映射文件&#xff0c;id 是否可以重复&#xff1f; 18、为什么说 Mybatis 是半自动 ORM 映射…

Vue项目搭建图文详解教程

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 预备工作 请在本地创建文件夹用于存放Vue项目&#xff0c;例如&#xff1a;创建HelloWorld文件夹存放即将创建的Vue新项目。 创建Vue项目 首先&#xff0c;请在DOS中将目录…

踩坑 | vue动态绑定img标签src属性的一系列报错

文章目录 踩坑 | vue项目运行后使用require()图片也不显示问题描述vue中动态设置img的src不生效问题的原因require is not defined 解决办法1&#xff1a;src属性直接传入地址解决办法2 踩坑 | vue项目运行后使用require()图片也不显示 问题描述 在网上查阅之后&#xff0c;发…

深度学习笔记之线性代数

深度学习笔记之线性代数 一、向量 在数学表示法中&#xff0c;向量通常记为粗体小写的符号&#xff08;例如&#xff0c;x&#xff0c;y&#xff0c;z&#xff09;当向量表示数据集中的样本时&#xff0c;它们的值具有一定的现实意义。例如研究医院患者可能面临的心脏病发作风…

<C++> STL_bitset使用和模拟实现

bitset的介绍 位图的引入 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何快速判断一个数是否在这40亿个数中&#xff1f; 要判断一个数是否在某一堆数中&#xff0c;我们可能会想到如下方法&#xff1a; 将这一堆数进行排序&#xff0…

Linux-正则三剑客

目录 一、正则简介 1.正则表达式分两类&#xff1a; 2.正则表达式的意义 二、Linux三剑客简介 1.文本处理工具&#xff0c;均支持正则表达式引擎 2.正则表达式分类 3.基本正则表达式BRE集合 4.扩展正则表达式ere集合 三、grep 1.简介 2.实践 3.贪婪匹配 四、sed …

STM32Cubemx新建F429基础工程

配置STM32CubeMX 配置KEY 配置USART1 配置RCC Project Manager Toolchain 选择 MDK-ARM Code Generator 配置如下 GENERATE CODE 即可 配置Keil5 魔术棒配置 – Target – 勾选 Use MicroLIB – Debug – Flash Download – 勾选Reset and Run 基础代码 /* Private incl…

GD32F103x IIC通信

1. IIC通信 1.IIC的介绍 IIC总线有两条串行线&#xff0c;其一是时钟线SCK&#xff08;同步&#xff09;&#xff0c;其二是数据线SDA。只有一条数据线属于半双工。应用中&#xff0c;单片机常常作为主机&#xff0c;外围器件可以挂载多个。&#xff08;当然主机也可以有多个。…