springcloud:对象存储组件MinIO

news2024/11/26 7:52:34

类似于FastDFS/HDFS的一个文件存储服务!

SpringBoot整合MinIO实现分布式文件服务!

#MinIO简介?

Minio 是个基于 Golang 编写的开源对象存储套件,基于Apache License v2.0开源协议,虽然轻量,却拥有着不错的性能。它兼容亚马逊S3云存储服务接口。可以很简单的和其他应用结合使用,例如 NodeJS、Redis、MySQL等。

#1. 应用场景

MinIO 的应用场景除了可以作为私有云的对象存储服务来使用,也可以作为云对象存储的网关层,无缝对接 Amazon S3 或者 MicroSoft Azure

#2. 特点

  1. 高性能:作为一款高性能存储,在标准硬件条件下,其读写速率分别可以达到 55Gb/s 和 35Gb/s。并且MinIO 支持一个对象文件可以是任意大小,从几kb到最大5T不等。

  2. 可扩展:不同MinIO集群可以组成联邦,并形成一个全局的命名空间,并且支持跨越多个数据中心。

  3. 云原生:容器化、基于K8S的编排、多租户支持。

  4. Amazon S3兼容:使用 Amazon S3 v2 / v4 API。可以使用Minio SDK,Minio Client,AWS SDK 和 AWS CLI 访问Minio服务器。

  5. SDK支持:

    • GO SDK:GitHub - minio/minio-go: MinIO Go client SDK for S3 compatible object storage(opens new window)

    • JavaSDK:GitHub - minio/minio-java: MinIO Client SDK for Java(opens new window)

    • PythonSDK:GitHub - minio/minio-py: MinIO Client SDK for Python(opens new window)

  6. 图形化界面:有操作页面

  7. 支持纠删码:MinIO使用纠删码、Checksum来防止硬件错误和静默数据污染。在最高冗余度配置下,即使丢失1/2的磁盘也能恢复数据。

功能很强大~

源码地址:GitHub - minio/minio: High Performance Object Storage for AI(opens new window)

中文文档地址:MinIO | 高性能, Kubernetes原生对象存储(opens new window)

#安装MinIO

安装非常简单,这里使用docker安装,步骤如下:

#1. 获取镜像

执行命令如下:

docker pull minio/minio

#2. 启动镜像

执行命令如下:

mkdir -p /opt/mnt/data /opt/mnt/conf
docker run -p 9000:9000 -p 9099:9099 --name minio -d --restart=always -e "MINIO_ACCESS_KEY=admin" -e "MINIO_SECRET_KEY=admin123456789"  -v /opt/mnt/data:/data -v /opt/mnt/config:/root/.minio minio/minio server --console-address ":9000" --address ":9099" /data

命令解释如下:

  • -p:9000是图形界面的端口,9001是API的端口,在使用SDK连接需要用到

  • MINIO_ACCESS_KEY:指定图形界面的用户名

  • MINIO_SECRET_KEY:指定图形界面的密码

按照上述两个步骤启动成功即可。

注意:ACCESS_KEY 长度最少3个字符,SECRET_KEY 长度最少8个字符

#3. 图形界面操作

安装成功后直接访问地址:http:/ip:9000/login,如下:

输入用户名和密码登录成功后,如下:

菜单很多,这里就不再详细介绍了,笔者这里直接在Buckets菜单中创建一个桶为test,如下图:

并且设置这个桶的隐私规则为public,如下:

MinIO到此已经安装设置成功了

#SpringBoot整合MinIO上传文件

要实现SDK上传需要检查存放图片data文件是否为最高权限,不然上传接口会报错:

S3 API Requests must be made to API port

原因:权限不够不能创建对应文件路径
解决方案:

检查docker映射的data目录 /opt/mnt/data权限,如果权限不够 chmod 777 /opt/mnt/data

虽然MinIO在图形界面提供了手动上传的操作,但是也可以通过SDK的方式去上传,下面介绍一下Spring Boot 整合MinIO上传文件。

#1. 获取accessKey和secretKey

这里的accessKey和secretKey并不是图形界面登录名和密码,获取很简单,直接在图形界面中操作,如下图:

#2. 添加依赖

添加MinIO的依赖,如下:

<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.5.3</version>
</dependency>

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.10.0</version>
</dependency>

#3. 添加配置

minio:
  # minio地址
  endpoint: http://localhost:9000
  # 账户
  username: minioadmin
  # 密码
  password: minioadmin
  defaultBucketName: test

#4. 创建配置类,用于生成MinioClient

/**
 * @Description minio配置类
 */
@Configuration
public class MinioConfig {

    @Value("${minio.endpoint}")
    private String endpoint;

    @Value("${minio.username}")
    private String username;

    @Value("${minio.password}")
    private String password;

    @Value("${minio.defaultBucketName}")
    private String defaultBucketName;

    @Bean
    public MinioClient minioClient(){
        return MinioClient.builder().credentials(username, password).endpoint(endpoint).build();
    }

}

#5.创建一个返回实体类,方便规范返回信息

@Data
public class MinioReturn {

    /**
     * 文件地址
     */
    private String path;

    /**
     * 原始文件名
     */
    private String inputName;

    /**
     * 最终文件名
     */
    private String outPutName;

}

#6.创建MinioTemplate类,用来书写minio工具类

@Component
public class MinioTemplate {

    @Autowired
    private MinioClient minioClient;

    private static final String SLASH = "/";

    @Value("${minio.defaultBucketName}")
    private String defaultBucketName;

    @Value("${minio.endpoint}")
    private String endpoint;

    /**
     * 创建桶
     *
     * @param bucketName
     * @throws Exception
     */
    public void makeBucket(String bucketName) throws Exception {
        BucketExistsArgs args = BucketExistsArgs.builder().bucket(bucketName).build();
        if (!minioClient.bucketExists(args)) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     * 上传文件
     *
     * @param file
     * @return
     * @throws Exception
     */
    public MinioReturn putFile(MultipartFile file) throws Exception {
        return putFile(file, file.getOriginalFilename(), defaultBucketName);
    }

    public MinioReturn putFile(MultipartFile file, String fileName, String bucketName) throws Exception {
        if (bucketName == null || bucketName.length() == 0) {
            bucketName = defaultBucketName;
        }
        makeBucket(bucketName);
        minioClient.putObject(PutObjectArgs.builder()
                .bucket(bucketName)
                .object(fileName)
                .stream(file.getInputStream(), file.getSize(), -1)
                .contentType(file.getContentType())
                .build());
        return new MinioReturn(fileLink(bucketName, fileName), file.getOriginalFilename(), fileName);
    }

    /**
     * 删除文件
     *
     * @param bucketName
     * @param fileName
     * @throws Exception
     */
    public void removeFile(String bucketName, String fileName) throws Exception {
        minioClient.removeObject(RemoveObjectArgs.builder()
                .bucket(bucketName == null || bucketName.length() == 0 ? defaultBucketName : bucketName)
                .object(fileName)
                .build());
    }

    @SneakyThrows
    private String fileLink(String bucketName, String fileName) {
        return endpoint.concat(SLASH).concat(bucketName).concat(SLASH).concat(fileName);
    }

    private String getFileName(String fileName) {
        return getFileName(null, fileName);
    }

    private String getFileName(String prefix, String fileName) {
        String fileNamePre = fileName;
        String fileType = "";
        int index = fileName.lastIndexOf(".");
        if (index > 0) {
            fileNamePre = fileName.substring(0, index);
            fileType = fileName.substring(index);
        }
        String name = UUID.randomUUID().toString().replace("-", "");
        if (!org.springframework.util.StringUtils.isEmpty(fileNamePre)) {
            name = fileNamePre + "-" + name + fileType;
        }
        if (!StringUtils.isEmpty(prefix)) {
            name = prefix + "-" + name;
        }
        return name;
    }


}

#7.书写控制类,用于测试

@RestController
@RequestMapping("minio")
@AllArgsConstructor
public class MinioController {

    private final MinioTemplate minioTemplate;

    @PostMapping("/upload")
    @ResponseBody
    public MinioReturn upload(MultipartFile file) throws Exception {
        return minioTemplate.putFile(file);
    }

    @PostMapping("/remove")
    @ResponseBody
    public String remove(String fileName, String bucketName) throws Exception{
        minioTemplate.removeFile(bucketName, fileName);
        return "success";
    }

}

#8. 测试

我们查看minio中,自动创建了桶,并且文件也上传成功了

同样再测试一下删除接口

在这里插入图片描述
查看minio中删除成功

在这里插入图片描述

如果想通过配置域名映射minio服务器访问指定图片:

桶权限设置为public

在这里插入图片描述

上述代码创建的桶默认是private的,如果想要通过客户端代码调整桶权限的话,可以通过minioClient.setBucketPolicy方法,设置完后可以通过返回的地址进行访问,如下所示(如果想要通过外网访问,给对应的内网地址端口做个外网映射即可)

在这里插入图片描述

开启权限public会有个安全问题,那就是当你访问桶路径时,会发现会把所有桶下的文件列出来,这样只要再拼接上文件名就能访问所有文件了

在这里插入图片描述

要解决这个问题,只需要将权限设置为custom,然后将"s3:ListBucket"取消即可

在这里插入图片描述
再次访问会发现权限禁止,而加上文件名后是可以正常查看的
在这里插入图片描述

当然,也可以使用AmazonS3 云存储服务接口

相关文档:Amazon S3对象执行操作 - AWS SDK for Java1.x

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

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

相关文章

低代码开发平台的优势及应用场景分析

文章目录 低代码是什么&#xff1f;低代码起源低代码分类低代码的能力低代码的需求市场需要专业开发者需要数字化转型需要 低代码的趋势如何快速入门低代码开发低代码应用领域 低代码是什么&#xff1f; 低代码&#xff08;Low-code&#xff09;是著名研究机构Forrester于2014…

JS中的模板字符串(ES6中的模板字面量语法),什么是模板字符串、怎么使用,附代码演示

模板字符串 1、JavaScript 在 ES6 新增了模板字符串语法。模板字符串可以作为普通字符串使用&#xff0c;其作用是可以在字符串中换行&#xff08;也就是支持多行字符串&#xff09;以及将变量和表达式插入字符串。 2、整个语法&#xff1a;使用反引号 &#xff0c;而不是单引…

如何绘制甘特图?

甘特图(Gantt chart) 又叫横道图、条状图(Bar chait)。它是在第一次世界大战时期发明的&#xff0c;以亨利I甘特先生的名字命名&#xff0c;他制定了一个完整地用条形图表进度的标志系统。甘特图内在思想简单&#xff0c;即以图示的方式通过活动列表和时间刻度形象地表示出任何…

【C++高阶(七)】C++异常处理的方式

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; 异常处理的方式 1. 前言2. C语言处理异常的方式…

【密码学】群的证明(习题)

0.前置知识 1.习题 记录一次密码学作业~群的判定 2.求解

Chrome2023新版收藏栏UI改回旧版

版本 120.0.6099.109&#xff08;正式版本&#xff09;Chrome浏览器菜单新版、旧版的差异 想要将书签、功能内容改回旧版的朋友可以网址栏输入&#xff1a;「chrome://flags」&#xff0c;接着搜寻「Chrome Refresh 2023」。 最后将 Chrome Refresh 2023、Chrome Refresh 2023…

HNU-数据库系统-实验1-数据定义/数据操纵

数据库系统 课程实验1数据定义/数据操纵 计科210X 甘晴void 202108010XXX 目录 文章目录 数据库系统 课程实验1<br>数据定义/数据操纵实验目的实验样例实验环境实验内容1.1 数据库定义1&#xff09;实验内容与要求2&#xff09;实验重难点3&#xff09;实验基础知识①模…

【JAVA-Day69】抛出异常的精髓:深度解析 throw、throws 关键字,优雅处理异常问题

抛出异常的精髓&#xff1a;深度解析 throw、throws 关键字&#xff0c;优雅处理异常问题 &#x1f680; 抛出异常的精髓&#xff1a;深度解析 throw、throws 关键字&#xff0c;优雅处理异常问题 &#x1f680;一、什么是抛出异常 &#x1f60a;二、如何抛出异常 &#x1f914…

复合型下拉框

element只提供了复合型输入框&#xff0c;复合型下拉框的效果&#xff0c;我是通过button与el-select拼接形成的&#xff0c;代码如下&#xff1a; <div class"form"><button class"btn">是否需要审核</button><el-select v-model&q…

C语言之文件操作(上)

C语言之文件操作&#xff08;上&#xff09; 文章目录 C语言之文件操作&#xff08;上&#xff09;1. 什么是⽂件&#xff1f;1.1 程序⽂件1.2 数据⽂件1.3 ⽂件名 2. ⼆进制⽂件和⽂本⽂件3. ⽂件的打开和关闭3.1 流和标准流3.1.1 流3.1.2 标准流 4. ⽂件指针5. 文件的打开与关…

c语言:制造简单的计算器|练习题

一、题目 制造一个简单的计算器。输入两个数&#xff0c;计算加减乘除的结果。 如图&#xff1a; 二、代码截图【带注释】 三、源代码【带注释】 #include int main() { int yunSuanFu0;//定义运算符符号变量 int num1,num2;//定义要输入的两个数字 cc: printf(…

VUE中的8种常规通信方式

文章目录 1.props传递数据(父向子)2.$emit触发自定义事件&#xff08;子向父&#xff09;3.ref&#xff08;父子&#xff09;4.EventBus&#xff08;兄弟组件&#xff09;5.parent或root&#xff08;兄弟组件&#xff0c;有共同祖辈&#xff09;6.attrs和listeners&#xff08;…

基于Java+Swingt学生信息管理系统

基于JavaSwing学生信息管理系统 一、系统介绍二、功能展示四、其他系统实现五、获取源码 一、系统介绍 1.用户登陆&#xff1a;在帮助按钮处&#xff0c;可以查看登陆账号及密码&#xff1a; 账号admin,密码123456 在未输入的情况下&#xff0c;会提示用户名不能为空&#xff…

树专题 —— 深入理解经典红黑树

大家好&#xff0c;我是 方圆。本篇我们讲红黑树的经典实现&#xff0c;Java中对红黑树的实现便采用的是经典红黑树。前一篇文章我们介绍过左倾红黑树&#xff0c;它相对来说比较简单&#xff0c;需要大家看完上篇再来看这一篇&#xff0c;因为旋转等基础知识不会再本篇文章中赘…

程序人生15年人生感悟

计算机程序员并不是一件什么高大上的职业。而仅仅是一份普通的工作。就像医生能治病救人&#xff0c;我们能治蓝屏救程序&#xff0c;我们都在为这个世界默默的做出自己的贡献。刻意或无意宣扬某个职业高大上&#xff0c;其实质是对其它行业从业者的不公平。但是有些人却常常这…

防火墙 设置 出站规则

测试需求&#xff1a;禁止10000端口出站&#xff0c;用于测试 搜索栏 &#xff0c;输入防火墙&#xff0c;打开防火墙和网络保护&#xff0c;打开高级设置 新建一个出站规则 新建规则 &#xff0c;自定义、 这样就建好了 同时确保 防火墙&#xff0c;至少有一个打开着&#xf…

java:微服务springcloud入门以及eureka、ribbon、hystrix、feign、gateway的使用

文章目录 微服务架构Spring Cloud微服务或Spring Cloud的工作流程&#xff1a;常见注册中心技术常见的负载均衡技术常见的熔断器技术常见的配置管理技术常见的网关技术常见的消息追踪技术常见的消息总线技术示例&#xff1a;服务注册发现eureka的使用Eureka服务器服务消费者&am…

深入探索Spring Batch:大规模批处理的领航者

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 写在前面参与规则 ✅参与方式&#xff1a;关注博主、点赞、收藏、评论&#xff0c;任意评论&#xff08;每人最多评论…

鸿蒙 Ark ui 实战登录界面请求网络实现教程

团队介绍 作者&#xff1a;徐庆 团队&#xff1a;坚果派 公众号&#xff1a;“大前端之旅” 润开鸿生态技术专家&#xff0c;华为HDE&#xff0c;CSDN博客专家&#xff0c;CSDN超级个体&#xff0c;CSDN特邀嘉宾&#xff0c;InfoQ签约作者&#xff0c;OpenHarmony布道师&…

备赛笔记——2024全国职业院校技能大赛“大数据应用开发”赛项——任务2:离线数据处理

MySQLhttps://www.mysql.com/ 将下发的ds_db01.sql数据库文件放置mysql中 12、编写Scala代码&#xff0c;使用Spark将MySQL的ds_db01库中表user_info的全量数据抽取到Hive的ods库中表user_info。字段名称、类型不变&#xff0c;同时添加静态分区&#xff0c;分区字段为etl_da…