在 Spring Boot 中集成 MinIO 对象存储

MinIO 是一个开源的对象存储服务器,专注于高性能、分布式和兼容S3 API的存储解决方案。本文将介绍如何在 Spring Boot 应用程序中集成 MinIO,以便您可以轻松地将对象存储集成到您的应用中。

安装minio

  1. 拉取 minio Docker镜像

    docker pull minio/minio
    
  2. 创建minio数据和配置目录

    mkdir -p /data/minio/data /data/minio/config
    
  3. 运行minio容器,设置访问和密钥并挂载数据卷

    docker run -p 9090:9090 -p 9000:9000 --name minio \
      -v ~/data/minio/data:/data \
      -v ~/data/minio/config:/root/.minio \
      -e "MINIO_ACCESS_KEY=minio" \
      -e "MINIO_SECRET_KEY=minio123" \
      minio/minio server /data --console-address ":9090"
    

或者 使用 docker-compose.yml

version: '3.9'
services:
    minio:
        command: 'server /data --console-address ":9090"'
        image: minio/minio
        environment:
            - MINIO_SECRET_KEY=minio123
            - MINIO_ACCESS_KEY=minio
        volumes:
            - '~/data/minio/config:/root/.minio'
            - '~/data/minio/data:/data'
        container_name: minio
        ports:
            - '9000:9000'
            - '9090:9090'

  • mkdir``~/minio/data在您的主目录中创建一个新的本地目录。
  • docker run启动 MinIO 容器。
  • -p将本地端口绑定到容器端口。
  • -name为容器创建一个名称。
  • -v将文件路径设置为容器要使用的持久卷位置。当 MinIO 将数据写入 时/data,该数据会镜像到本地路径~/minio/data,从而允许其在容器重新启动之间保留。您可以替换~/minio/data为用户具有读取、写入和删除访问权限的另一个本地文件位置。
  • -e分别设置环境变量MINIO_ROOT_USERMINIO_ROOT_PASSWORD。这些设置root 用户凭据。更改用于您的容器的示例值。

运行结果

WARNING: MINIO_ACCESS_KEY and MINIO_SECRET_KEY are deprecated.
         Please use MINIO_ROOT_USER and MINIO_ROOT_PASSWORD
Formatting 1st pool, 1 set(s), 1 drives per set.
WARNING: Host local has more than 0 drives of set. A host failure will result in data becoming unavailable.
MinIO Object Storage Server
Copyright: 2015-2023 MinIO, Inc.
License: GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html>
Version: RELEASE.2023-08-29T23-07-35Z (go1.19.12 linux/amd64)

Status:         1 Online, 0 Offline. 
S3-API: http://172.17.0.2:9000  http://127.0.0.1:9000 
Console: http://172.17.0.2:9090 http://127.0.0.1:9090 

Documentation: https://min.io/docs/minio/linux/index.html
Warning: The standard parity is set to 0. This can lead to data loss.
  1. 登录 控制台 http://127.0.0.1:9090/browser 用户名密码是你启动时初始化的这里是 minio、minio123
  2. 创建 桶(Buckets)
    在这里插入图片描述

参考:

  1. https://min.io/docs/minio/container/index.html

Spring Boot 集成

1. 添加 MinIO 客户端依赖

在您的 Spring Boot 项目的 pom.xml 文件中添加 MinIO 客户端依赖:

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

接下来,您需要在您的Spring Boot应用程序中配置MinIO客户端。您可以在application.propertiesapplication.yml文件中添加以下配置:

# MinIO配置
minio.endpoint=http://localhost:9000  # MinIO服务器的地址
minio.access-key=minio     # 您的访问密钥
minio.secret-key=minio123     # 您的秘密密钥

2. 创建 MinIO 配置类

创建一个配置类,用于初始化 MinIO 客户端。创建一个名为 MinioConfig 的类:

import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MinioConfig {

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

    @Value("${minio.access-key}")
    private String accessKey;

    @Value("${minio.secret-key}")
    private String secretKey;

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

3. 集成 MinIO 操作到您的应用

您可以在您的服务或控制器中使用 MinioClient 来进行 MinIO 操作。以下是一个上传文件到 MinIO 的示例:


import io.minio.GetObjectArgs;
import io.minio.GetObjectResponse;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import okhttp3.Headers;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

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

    @Autowired
    private MinioClient minioClient;

    @PostMapping("/upload")
    public String uploadFile(@RequestParam("file") MultipartFile file) {
        try {
            /**
             * 使用 UUID 作为对象名称:
             * 1. 唯一性,避免对象名称冲突。
             * 2. 隐藏实际文件信息,提高一定的隐私。
             * 3. 对象名称不受原始文件名长度或特殊字符的限制。
             * 在实际场景中,如果你更注重文件的可识别性和管理,可以考虑使用文件名称。如果你更注重唯一性和隐私性,可以考虑使用 UUID。
             * 同时,你也可以结合两者,例如将文件名作为对象属性存储,然后使用 UUID 作为对象名称。这样既可以保留文件信息,又能保证唯一性。
             */
            String objectName = UUID.randomUUID().toString();
            Map<String, String> metadata = new HashMap<>();
            metadata.put("originalFilename", file.getOriginalFilename());

            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket("firsttest")
                            .object(objectName)
                            .userMetadata(metadata)
                            .stream(file.getInputStream(), file.getSize(), -1)
                            .contentType(file.getContentType())
                            .build()
            );
            return "File uploaded successfully!  fileId: " + objectName;
        } catch (Exception e) {
            return "Error uploading file: " + e.getMessage();
        }
    }

    @GetMapping("/download/{filename}")
    public ResponseEntity<InputStreamResource> downloadFile(@PathVariable("filename") String filename) {
        try {
            Optional<GetObjectResponse> inputStream = Optional.ofNullable(minioClient.getObject(
                    GetObjectArgs.builder()
                            .bucket("firsttest")
                            .object(filename)
                            .build()
            ));
            if (inputStream.isPresent()) {
                InputStreamResource resource = new InputStreamResource(inputStream.get());
                Headers headers = inputStream.get().headers();
                ResponseEntity.BodyBuilder bodyBuilder = ResponseEntity.ok();
                String mediaType = headers.get("Content-Type");
                if (StringUtils.isNotEmpty(mediaType)) {
                    bodyBuilder.contentType(MediaType.parseMediaType(mediaType));
                }
                return bodyBuilder.header("Content-Disposition", "attachment; filename=" + URLEncoder.encode(headers.get("X-Amz-Meta-originalfilename"), StandardCharsets.UTF_8))
                        .body(resource);
            } else {
                return ResponseEntity.notFound().build();
            }
        } catch (Exception e) {
            return ResponseEntity.badRequest().body(null);
        }
    }

}

使用 UUID 作为对象名称:

  1. 唯一性,避免对象名称冲突。
  2. 隐藏实际文件信息,提高一定的隐私。
  3. 对象名称不受原始文件名长度或特殊字符的限制。

在实际场景中,如果你更注重文件的可识别性和管理,可以考虑使用文件名称。如果你更注重唯一性和隐私性,可以考虑使用 UUID。
同时,你也可以结合两者,例如将文件名作为对象属性存储,然后使用 UUID 作为对象名称。这样既可以保留文件信息,又能保证唯一性。

http://127.0.0.1:80/minio/upload 上传完毕成功后,控制台查看文件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

自定义 metadata 为啥前缀有 X-Amz-Meta-?

在 MinIO 中,当你设置自定义元数据(metadata)时,MinIO 会遵循 Amazon S3 的元数据规范,其中元数据的键名> 前会添加 x-amz-meta- 前缀。这是因为 MinIO 是一个兼容 Amazon S3 API 的对象存储服务器,因此它采用了 Amazon > S3 的一些规范和约定。
Amazon S3 使用 x-amz-meta- 前缀来标识用户自定义的元数据,以便与 Amazon S3 内部使用的标准元数据进行区> 分。这样可以确保用户自定义的元数据不会与 S3 内部使用的元数据冲突。这也是为了保持兼容性,使 MinIO 用户可以> 使用与 Amazon S3 相同的元数据命名约定。
因此,在 MinIO 中设置自定义元数据时,不需要手动添加 x-amz-meta- 前缀,MinIO 会自动处理这个前缀,确保它符合 Amazon S3 的规范。当你从对象中检索元数据时,MinIO 也会自动解析并返回合适的键名,不包含前缀。
总之,这个前缀是 MinIO 为了兼容 Amazon S3 API,保持统一性而引入的。

请注意,上述示例仅为基本示例,用于展示如何在Spring Boot中集成MinIO。您可以根据您的实际需求进行更多的配置和操作。确保替换示例中的"your-access-key"、“your-secret-key”、"your-bucket-name"和其他参数为您自己的值。

最后,不要忘记在您的MinIO服务器上创建对应的存储桶(Bucket),以及设置正确的访问权限。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解决 .csv 文件上传到 pgsql 的字符报错问题

目录 背景问题解决办法 背景 上传 .csv 文件进行数据导入到 pg 时&#xff0c;报错显示如下&#xff1a; ods.tbl_inp_fee_detail.csv数据上传失败 报错信息:org.postgresql.util.PSQLException: ERROR: invalid byte sequence for encoding "UTF8": 0x00 Where: C…

多维时序 | Matlab实现GRU-Adaboost和GRU多变量时间序列预测对比

多维时序 | Matlab实现GRU-Adaboost和GRU多变量时间序列预测对比 目录 多维时序 | Matlab实现GRU-Adaboost和GRU多变量时间序列预测对比预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 多维时序 | Matlab实现GRU-Adaboost和GRU多变量时间序列预测对比 模型描述 M…

【python爬虫】10.指挥浏览器自动工作(selenium)

文章目录 前言selenium是什么怎么用设置浏览器引擎获取数据解析与提取数据自动操作浏览器 实操运用确认目标分析过程代码实现 本关总结 前言 上一关&#xff0c;我们认识了cookies和session。 分别学习了它们的用法&#xff0c;以及区别。 还做了一个项目&#xff1a;带着小…

Redis集群操作-----主从互换

一、将节点cluster1的主节点7000端口的redis关掉 [rootredis-cluster1 src]# ps -ef |grep redis 二、查看集群信息&#xff1a;

SpringBoot复习:(60)文件上传的自动配置类MultipartAutoConfiguration

可以看到&#xff0c;定义了一个类型为StandartServletMultipartResolver的bean 用来进行文件上传&#xff0c;定义了一个类型为MultipartConfigElement的bean用来进行上传相关的配置&#xff0c;其中使用了MultipartProperties中的属性&#xff0c;这个类的定义如下&#xff1…

Centos 6.5 升级到Centos7指导手册

一、背景 某业务系统因建设较早&#xff0c;使用的OS比较过时&#xff0c;还是centos6.5的系统&#xff0c;因国产化需要&#xff0c;需将该系统升级到BClinux 8.6&#xff0c;但官方显示不支持centos 6.x升级到8&#xff0c;需先将centos6.5升级到centos7的最新版&#xff0c…

ZDH-权限模块

本次介绍基于ZDH v5.1.2版本 目录 项目源码 预览地址 安装包下载地址 ZDH权限模块 ZDH权限模块-重要名词划分 ZDH权限模块-菜单管理 ZDH权限模块-角色管理 ZDH权限模块-用户配置 ZDH权限模块-权限申请 项目源码 zdh_web: GitHub - zhaoyachao/zdh_web: 大数据采集,抽…

高频面试题:如何分别用三种姿势实现三个线程交替打印0到100

最近面试遇到的一道题&#xff0c;需要三个线程交替打印0-100&#xff0c;当时对多线程并不是很熟悉因此没怎么写出来&#xff0c;网上搜了之后得到现 synchronized wait/notifyAll 实现思路&#xff1a;判断当前打印数字和线程数的取余&#xff0c;不等于当前线程则处于等待…

ORB-SLAM3复现过程中遇到的问题及解决办法

在复现过程中遇到的问题的解决过程 1. 版本检查1.1 Opencv版本的检测1.2 Eigen版本的检测1.3 查看Python版本1.4 其他 2. 编译过程中遇到的问题及解决办法2.1 ./build.sh遇到的问题2.2 ./build_ros.sh遇到的问题 因为环境比较干净&#xff0c;所以遇到的问题相对少一些&#xf…

多线程的五种“打开”方式

1 概念 1.1 线程是什么&#xff1f;&#xff1f; 线程&#xff08;Thread&#xff09;是计算机科学中的一个基本概念&#xff0c;它是进程&#xff08;Process&#xff09;中的一个执行单元&#xff0c;负责执行程序的指令序列。线程是操作系统能够进行调度和执行的最小单位。…

MariaDB数据库服务器

目录 一、什么是数据库&#xff1f; 二、什么是关系型数据库&#xff1f; 三、数据库字符集和排序规则是什么&#xff1f; 四、常用数据类型 五、Mariadb数据库相关配置案例 一、什么是数据库&#xff1f; 数据库&#xff08;DB&#xff09;是以一定方式长期存储在计算机硬盘内…

PHP8内置函数中的数学函数-PHP8知识详解

php8中提供了大量的内置函数&#xff0c;以便程序员直接使用常见的内置函数包括数学函数、变量函数、字符串函数、时间和日期函数等。今天介绍内置函数中的数学函数。 本文讲到了数学函数中的随机数函数rand()、舍去法取整函数floor()、向上取整函数 ceil()、对浮点数进行四舍…

1.频偏估计算法

目录 整数倍频偏估计方法 小数倍频偏估计方法 使用CP进行频偏估计 使用SSB进行频偏估计 OFDM对频偏比较敏感&#xff0c;频偏会影响子载波的正交性&#xff0c;造成载波间干扰。频偏对PRACH相关计算峰值的影响本质上是子载波间干扰导致的。时域检测&#xff1a;首先对接收…

聚合多个电商API接口平台

API接口测试&#xff08;点击免费测试&#xff09; 随着数字化商业时代的到来&#xff0c;API接口已成为电商资源连接利器&#xff0c;也是全球传统互联网企业转型的基础。 2021年 Google Cloud 研究显示&#xff0c;全球互联网企业近3/4的企业持续投入数字化转型&#xff0c…

最佳实践:TiDB 业务读变慢分析处理

作者&#xff1a;李文杰 网易游戏计费 TiDB 负责人 在使用或运维管理 TiDB 的过程中&#xff0c;大家几乎都遇到过 SQL 变慢的问题&#xff0c;尤其是查询相关的读变慢问题。读变慢的问题大部分情况下都遵循一定的规律&#xff0c;通过经验的积累可以快速的定位和优化&#xff…

【倒着考虑】CF Edu 21 D

Problem - D - Codeforces 题意&#xff1a; 思路&#xff1a; 这道题需要倒着步骤考虑&#xff0c;就是先去假设已经分为了两部分&#xff0c;这左右两部分的和相等&#xff0c;然后去想上一个步骤 倒着一个步骤后&#xff0c;可以发现这样的性质&#xff1a; Code&#xf…

C++:初识类与this指针

文章目录 前言一、类类的定义和实例化类的访问限定符类的作用域计算类的大小 二、类的成员函数的this指针总结 个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》 前言 一、类 类的定义和实例化 注意类定义结束时后面分号( ; )不能省略。 类…

【算法刷题-栈与队列篇】

目录 1.leetcode-232. 用栈实现队列2.leetcode-225. 用队列实现栈3.leetcode-20. 有效的括号&#xff08;1&#xff09;代码1&#xff08;2&#xff09;代码2 4.leetcode-1047. 删除字符串中的所有相邻重复项5.leetcode-150. 逆波兰表达式求值6.leetcode-239. 滑动窗口最大值7.…

关于一个git的更新使用流程

1.第一步使用git bash 使用git bash命令来进行操作&#xff08;当然我是个人比较喜欢用这种方法的&#xff09; 2. 第二步&#xff1a;连接 3.第三步&#xff1a;进入 4.第四步&#xff1a;查看分支 5.第五步&#xff1a;切换分支 将本地文件更新后之后进行提交 6.第六步&am…

猫头虎博主赠书一期:《Kubernetes原生微服务开发》

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…