在 Spring Boot 中集成 MinIO 对象存储

news2024/11/27 20:58:12

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"
    
    • 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.
    
  4. 登录 控制台 http://127.0.0.1:9090/browser 用户名密码是你启动时初始化的这里是 minio、minio123

  5. 创建 桶(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),以及设置正确的访问权限。

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

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

相关文章

Linux串口驱动

《I.MX6ULL 参考手册》第 3561 页的“Chapter 55 Universal Asynchronous Receiver/Transmitter(UART) I.MX6ULL串口原理 1.1UART与USART UART是异步通信&#xff0c;USART是异步/同步通信&#xff0c;比UART多了一条时钟线 USART 的全称是 Universal Synchronous/Asynchr…

【Dots之003】SystemAPI.Query相关基础笔记

1、SystemAPI.Query 注&#xff1a;SystemAPI.Query只能作为foreach中in的的子句 SystemAPI.Query<RefRO<LocalTransform>>().WithAll<Obstacle>()解析&#xff1a;对于每个具有LocalTransform和Obstacle的Entity&#xff1b;都会将LocalTransform的只读引…

VBA:对Excel单元格进行合并操作

Sub hb()Dim nn 3For i 3 To 18If Range("b" & i) <> Range("b" & i 1) ThenRange("b" & n & ":b" & i).Mergen i 1End IfNextEnd Sub

基于Java+SpringBoot+Mybaties-plus+Vue+ElementUI 高校汉服租赁网站的 设计与实现

一.项目介绍 高校汉服租赁网站分为普通用户以及管理员两类 普通用户&#xff1a; 注册、登录系统、查看汉服首页发帖公告信息、 交流论坛&#xff08;发帖、查看帖子、评论&#xff09;、 公告咨询&#xff08;查看公告以及评论&#xff09;、 汉服信息&#xff08;查…

UNIX网络编程卷一 学习笔记 第二十九章 数据链路访问

目前大多操作系统都为程序提供访问数据链路层的功能&#xff0c;此功能可提供以下能力&#xff1a; 1.能监视由数据链路层接收的分组&#xff0c;使得tcpdump之类的程序能运行&#xff0c;而无需专门的硬件设备来监视分组。如果结合使用网络接口进入混杂模式&#xff08;promis…

Mac 安装php多版本,brew安装php8.0

因为需要我要在mac上装两个php版本&#xff0c;先前我已经装过php7.4,下面我们逐步安装php8.0 开始安装8.0&#xff1a; 直接运行安装 brew install php8.0 遇到问题怀疑是仓库太老了&#xff0c;更新一下homebrew ,重新安装 brew update 安装成功了,不过看了下版本好像不能正…

海关发布限制日本水产品进口,占据我国进口多少?

在福岛发生核电站事故后&#xff0c;我国就已经暂停进口包括福岛、宫城和长野等在内的10个县的所有食品&#xff0c;以及10个县以外的蔬菜等。而在日本宣布排放核污水并且已经实施之后&#xff0c;海关在24日发布全面暂停进口原产地为日本的水产品&#xff08;含食用水生动物&a…

安装启动Stable Diffusion教程

一、下载源码 GitHub - AUTOMATIC1111/stable-diffusion-webui: Stable Diffusion web UI 二、安装miniconda 参考&#xff1a;安装启动yolo5教程_苍穹之跃的博客-CSDN博客 三、安装CUDA 参考&#xff1a;安装启动yolo5教程_苍穹之跃的博客-CSDN博客 四、创建虚拟环境 co…

前端三剑客中简单的两个:HTMLCSS

HTML&CSS 1&#xff0c;HTML1.1 介绍1.2 快速入门1.3 基础标签1.3.1 标题标签1.3.2 hr标签1.3.3 字体标签 1.4 图片、音频、视频标签1.5 超链接标签1.6 列表标签1.7 表格标签1.8 布局标签1.9 表单标签1.9.1 表单标签概述1.9.2 form标签属性1.9.3 代码演示 1.10 表单项标签 …

XmlDocument.SelectNodes 不起作用

今天采用Xpath读取Xml节点&#xff0c;怎么都读不出。 问题分析&#xff1a; 错误代码如下&#xff1a; XmlDocument xmlD new XmlDocument();xmlD.PreserveWhitespace true;xmlD.LoadXml(xStr);xmlD.SelectNodes("job-scheduling-data/schedule/job");经排查 do…

SSD的基础知识介绍

固态硬盘&#xff0c;英文名Solid State Disk或Solid State Drive&#xff0c;是一种以存储器作为永久性存储器的电脑存储设备。虽然SSD已不是使用“碟盘”来记存数据&#xff0c;也没有用于“驱动”的马达&#xff0c;但是人们依照命名习惯&#xff0c;仍然称为固态硬盘或固态…

前端list列表自定义图标并设置大小

前端list列表自定义图标并设置大小 一、前端list列表基础知识回顾 前端公有两种列表&#xff0c;一种是有序列表&#xff08;ol&#xff09;&#xff0c;一种是无序列表&#xff08;ul&#xff09;&#xff0c;它们的子元素都是&#xff08;li&#xff09;。 1.1 有序列表&a…

pdf转换成图片转换器在线怎么转?pdf转换成图片具体方法介绍

很多用户们都是比较喜欢使用pdf文档的&#xff0c;由于这种文件格式的便携性非常高&#xff0c;所以广泛的应用于工作和学习领域&#xff0c;再加上pdf文档可以随意转换成为其他的文件格式&#xff0c;更是让pdf文档受到了更多用户们的欢迎&#xff0c;那么pdf转换成图片转换器…

31 - 个人博客项目-02-定义模型

前提: settings.py已经连接数据库 两张表想要互相调用 必须定义主外键约束,外键定义在多的一方 (1). 新建 apps / user / models.py 创建用户相关模型类 from datetime import datetime from ext import dbclass User(db.Model):# 用户表id db.Column(db.Integer, primary…

hadoop学习:mapreduce入门案例四:partitioner 和 combiner

先简单介绍一下partitioner 和 combiner Partitioner类 用于在Map端对key进行分区 默认使用的是HashPartitioner 获取key的哈希值使用key的哈希值对Reduce任务数求模决定每条记录应该送到哪个Reducer处理自定义Partitioner 继承抽象类Partitioner&#xff0c;重写getPartiti…

Web网站服务器

目录 一、什么是Apache? 二、虚拟目录是什么&#xff1f; 三、Apcahe相关配置文件 四、httpd.conf主配置文件的常用配置参数 五、Web网站配置案例 5.1搭建基于用户的个人主页网站 5.2、配置虚拟目录 5.3、配置虚拟主机 5.3.1搭建两个基于IP地址的虚拟主机 5.3.2搭建两个基于域…

发布自己的npm包

1.初始化npm包 npm init 输入npm init后&#xff0c;一路默认即可初始化成功&#xff0c;如下&#xff1a; 初始化成功后会生成一个package.json文件 n&#xff08;以我的文件夹demo-npm-dir为例&#xff09; package.json配置如下&#xff1a; {"name": "n…

基于Java+SpringBoot+Vue前后端分离客户关系管理系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

2023年全国职业院校技能大赛网络系统管理赛项模块A:网络构建卷II

2023年全国职业院校技能大赛 GZ073网络系统管理赛项 模块A&#xff1a;网络构建 卷II 目 录 任务清单 &#xff08;一&#xff09;基础配置 &#xff08;二&#xff09;有线网络配置 &#xff08;三&#xff09;无线网络配置 &#xff08;四&#xff09;出口网络配置 &am…

商城二维码系统_二维码生成系统源码与设计_OctShop

OctShop开源商城系统自带了二维码生成系统&#xff0c;商城所有系统要使用二维码的地方都是统一由此二维码生成系统生成的。其中包括&#xff1a;店铺收款二维码&#xff08;H5/小程序&#xff09;、店铺二维码&#xff08;H5/小程序&#xff09;、订单核销二维码、优惠券线下核…