Minio篇:初识MinIO

1. MinIO快速入门

1.1.MinIO核心概念

下面介绍MinIO中的几个核心概念,这些概念在所有的对象存储服务中也都是通用的。

  • 对象(Object)

    对象是实际的数据单元,例如我们上传的一个图片。

  • 存储桶(Bucket)

    存储桶是用于组织对象的命名空间,类似于文件夹。每个存储桶可以包含多个对象。

  • 端点(Endpoint)

    端点是MinIO服务器的网络地址,用于访问存储桶和对象,例如http://192.168.xxx.xxx:9000

    注意:

    9000为MinIO的API的默认端口,前边配置的9001以为管理页面端口。

  • Access Key 和 Secret Key

    Access Key是用于标识和验证访问者身份的唯一标识符,相当于用户名。

    Secret Key是与Access Key关联的密码,用于验证访问者的身份。

1.2.MinIO控制台页面操作

 前提:需要把你的MinIO部署在linux系统上,具体部署过程可看:MinIO官方

1.登录

管理页面的http://192.168.xxx.xxx:9001,登录的用户名和密码为部署时在EnvironmentFile文件中配置的如下参数:

MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=minioadmin

2.创建存储桶

3.上传图片

4.访问图片

图片URL

由于MinIO提供了HTTP访问功能,所以可以通过浏览器直接访问对象。对象URL为MinIO的Endpoint+对象的存储路径,例如下图中的图片对象的URL为

192.168.xxx.xxx:9000/lease/a.jpg

访问权限

不出意外的话,使用浏览器访问上述URL,会得到如下响应,很显然是没有访问权限。

若想继续访问图片,需要修改图片所在桶的访问权限,如下图所示  

如上图所示,可选的访问权限共有三个选项,分别是PrivatePublicCustom,具体说明如下

  • Private

    只允许桶的所有者对该桶进行读写。

  • Public

    允许所有人对该桶进行读写。

  • Custom

    自定义访问权限。

若想将权限设置为只允许所有者写,但允许所有人读,就需要自定义访问权限。自定义访问权限,需要使用一个规定格式的JSON字符串进行描述,具体格式可参考官方文档

例如以下JSON字符串表达的含义是:允许(Allow)所有人(*)读取(s3:GetObject)指定桶(lease)的所有内容。

{
  "Statement" : [ {
    "Action" : "s3:GetObject",
    "Effect" : "Allow",
    "Principal" : "*",
    "Resource" : "arn:aws:s3:::lease/*"
  } ],
  "Version" : "2012-10-17"
}

重新访问:

192.168.xxx.xxx:9000/lease/a.jpg

 

2. 图片上传接口开发

2.1. Minio相关配置

下面为该接口的具体实现

@ConfigurationProperties(prefix = "minio")
@Data
public class MinioProperties {

    private String endpoint;

    private String accessKey;

    private String secretKey;
    
    private String bucketName;
}
  • 配置Minio Client

    • 引入Minio Maven依赖

<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
</dependency>
  • 配置Minio相关参数

    application.yml中配置Minio的endpointaccessKeysecretKeybucketName等参数

    minio:
      endpoint: http://<hostname>:<port>
      access-key: <access-key>
      secret-key: <secret-key>
      bucket-name: <bucket-name>
     注意:上述<hostname><port>等信息需根据实际情况进行修改。

新建一个MinioProperties类:

@ConfigurationProperties(prefix = "minio")
@Data
public class MinioProperties {

    private String endpoint;

    private String accessKey;

    private String secretKey;
    
    private String bucketName;
}

新建一个MinioConfiguration类:

@Configuration
@EnableConfigurationProperties(MinioProperties.class)
public class MinioConfiguration {

    @Autowired
    private MinioProperties properties;

    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder().endpoint(properties.getEndpoint()).credentials(properties.getAccessKey(), properties.getSecretKey()).build();
    }
}

新建一个工具类:MinioUtil

package com.gjh.lease.common.minio;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.multipart.MultipartFile;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Component
@Slf4j
public class MinioUtil {
    @Autowired
    private MinioProperties prop;
    @Autowired
    private MinioConfiguration minioConfiguration;

    @Resource
    private MinioClient minioClient;


    /**
     * 查看存储bucket是否存在
     * @return boolean
     */
    public Boolean bucketExists(String bucketName) {
        Boolean found;
        try {
            found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return found;
    }

    /**
     * 创建存储bucket
     * @return Boolean
     */
    public Boolean makeBucket(String bucketName) {
        try {
            minioClient.makeBucket(MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    /**
     * 删除存储bucket
     * @return Boolean
     */
    public Boolean removeBucket(String bucketName) {
        try {
            minioClient.removeBucket(RemoveBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    /**
     * 获取全部bucket
     */
    public List<Bucket> getAllBuckets() {
        try {
            List<Bucket> buckets = minioClient.listBuckets();
            return buckets;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }



    /**
     * 文件上传
     *
     * @param file 文件
     * @return Boolean
     */
    public String upload(MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        if (StringUtils.isBlank(originalFilename)){
            throw new RuntimeException();
        }
        String fileName = new SimpleDateFormat("yyyyMMdd").format(new Date()) +
                "/" + UUID.randomUUID() + "-" + file.getOriginalFilename();
//        String objectName = CommUtils.getNowDateLongStr("yyyy-MM/dd") + "/" + fileName;
        String objectName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + "/" + fileName;
        try {
            PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(prop.getBucketName()).object(objectName)
                    .stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
            //文件名称相同会覆盖
            minioClient.putObject(objectArgs);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return objectName;
    }

    /**
     * 预览图片
     * @param fileName
     * @return
     */
    public String preview(String fileName){
        // 查看文件地址
        GetPresignedObjectUrlArgs build = new GetPresignedObjectUrlArgs().builder().bucket(prop.getBucketName()).object(fileName).method(Method.GET).build();
        try {
            String url = minioClient.getPresignedObjectUrl(build);
            return url;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 文件下载
     * @param fileName 文件名称
     * @param res response
     * @return Boolean
     */
    public void download(String fileName, HttpServletResponse res) {
        GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(prop.getBucketName())
                .object(fileName).build();
        try (GetObjectResponse response = minioClient.getObject(objectArgs)){
            byte[] buf = new byte[1024];
            int len;
            try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()){
                while ((len=response.read(buf))!=-1){
                    os.write(buf,0,len);
                }
                os.flush();
                byte[] bytes = os.toByteArray();
                res.setCharacterEncoding("utf-8");
                // 设置强制下载不打开
                // res.setContentType("application/force-download");
                res.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
                try (ServletOutputStream stream = res.getOutputStream()){
                    stream.write(bytes);
                    stream.flush();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 查看文件对象
     * @return 存储bucket内文件对象信息
     */
    public List<Item> listObjects() {
        Iterable<Result<Item>> results = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(prop.getBucketName()).build());
        List<Item> items = new ArrayList<>();
        try {
            for (Result<Item> result : results) {
                items.add(result.get());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return items;
    }

    /**
     * 删除
     * @param fileName
     * @return
     * @throws Exception
     */
    public boolean remove(String fileName){
        try {
            minioClient.removeObject( RemoveObjectArgs.builder().bucket(prop.getBucketName()).object(fileName).build());
        }catch (Exception e){
            return false;
        }
        return true;
    }

}

2.2.开发图片上传接口

controller:

 @Operation(summary = "上传文件")
    @PostMapping("upload")
    public Result<String> upload(@RequestParam MultipartFile file) throws Exception {
        String objectName = minioUtil.upload(file);
        if(null != objectName){
            return Result.ok(properties.getEndpoint() + "/" +properties.getBucketName() + "/" + objectName);
        }
        return Result.fail();
    }

这样就可以实现文件上传了。

2.3.测试

 

实现了基于Minio实现文件上传!

03-11
<think>好的,我需要回答用户关于MinIO对象存储的介绍与使用的问题。首先,我得确认用户的需求是什么。用户提到了引用1、2、3,都是关于MinIO的基本信息和API使用,所以需要涵盖这些方面。 首先,要介绍MinIO是什么。根据引用1,MinIO是开源的对象存储服务器,支持AWS S3兼容的API。引用2也提到这一点,所以需要强调其兼容性和适用场景。 接下来,应该列出主要特性。比如高性能、可扩展性、数据安全这些点。用户可能关心它为什么适合不同规模的应用,这部分需要详细说明。 然后是架构与工作原理。对象存储的核心概念,比如桶和对象,需要解释清楚。引用3提到了JAVA API操作,可能涉及到存储结构,所以这部分要详细说明桶和对象的关系,以及如何通过API管理。 安装部署部分,用户可能需要基础的操作步骤。根据引用1的文档链接,可以推荐用户参考官网的Windows文档,但这里只需要简要说明支持的环境和基本安装方式,比如Docker部署。 使用场景方面,引用1提到适用于多种规模的应用,所以需要列举常见的使用案例,比如大数据、云存储等,让用户了解其应用范围。 客户端和API操作部分,引用3提到JAVA API,可以举一个上传文件的示例代码,帮助用户快速上手。同时,要提到其他语言的支持,如Python、Go,让用户知道有广泛的开发支持。 最后,安全问题也是重点。需要说明加密机制和访问控制,确保用户知道数据的安全性。 生成相关问题的时候,要围绕用户可能进一步想了解的内容,比如部署步骤、数据安全机制、与AWS S3的区别,以及性能优化等。这些问题需要覆盖用户可能有的后续疑问,引导他们深入学习和应用。 整个回答过程中,要保持结构清晰,分点说明,每个部分都结合引用中的信息,确保准确可靠。同时,使用中文,避免技术术语过于复杂,让不同层次的用户都能理解。 需要检查是否符合系统级指令,比如数学公式的格式是否正确,但这个问题中可能不涉及数学内容,所以不用特别处理。确保所有独立的内容正确使用LaTeX,但看起来这里主要是文字和代码块,所以代码部分用反引号包裹,正确高亮。 最后,生成的相关问题要覆盖用户可能感兴趣的方向,比如安装、安全、对比分析、API使用等,这样用户可以根据自己的需求进一步探索。 现在整合这些思路,形成一个结构化的回答,确保每个部分都自然衔接,引用标识正确添加,并且语言流畅易懂。</think>### MinIO对象存储介绍与使用 #### 1. **MinIO简介** MinIO 是一个高性能、开源的**对象存储服务器**,专为大规模数据存储设计。它兼容 AWS S3 API,支持私有云、混合云及边缘计算场景,适用于机器学习、大数据分析等需要高吞吐量的场景[^1][^2]。 #### 2. **核心特性** - **AWS S3兼容**:可直接使用 AWS S3 SDK 或工具操作 MinIO,迁移成本低。 - **高性能**:采用纠删码(Erasure Code)技术,实现数据高可用和快速恢复。 - **轻量可扩展**:单节点即可运行,支持横向扩展至数千节点。 - **数据安全**:支持客户端加密、服务端加密(SSE)及 TLS 传输加密[^1]。 #### 3. **架构与工作原理** MinIO 使用**对象存储模型**,数据以“对象”形式存储在“桶”(Bucket)中。每个对象包含: - **数据本身**(如文件内容) - **元数据**(如文件类型、创建时间) - **唯一标识符**(对象键) 例如,上传文件 `report.pdf` 到 `documents` 桶的路径为: $$ \text{对象键} = \text{documents/report.pdf} $$ #### 4. **安装与部署** **快速部署示例(Docker):** ```bash docker run -p 9000:9000 -p 9001:9001 minio/minio server /data --console-address ":9001" ``` 部署后可通过 `http://localhost:9000` 访问 API,`http://localhost:9001` 访问管理界面。 #### 5. **典型使用场景** - **云原生应用存储**:Kubernetes 持久化存储 - **备份与归档**:替代传统 NAS/SAN - **AI/ML 数据湖**:存储训练数据集与模型 #### 6. **客户端与API操作** **Java 上传文件示例(引用自[^3]):** ```java MinioClient client = MinioClient.builder() .endpoint("http://localhost:9000") .credentials("minioadmin", "minioadmin") .build(); client.putObject(PutObjectArgs.builder() .bucket("my-bucket") .object("photo.jpg") .stream(inputStream, -1, 10485760) // 10MB分片 .build()); ``` 其他语言(Python、Go等)可通过类似 SDK 操作。 #### 7. **数据安全机制** - **访问控制**:基于策略(Policy)的权限管理,支持 IAM 角色。 - **加密传输**:强制启用 TLS 1.3。 - **完整性校验**:通过哈希值验证数据一致性。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值