MINIO简要使用说明

一、项目信息说明

minio Server版本:linux-amd64/minio 与 windows-amd64/minio.exe
minio Client版本:linux-amd64/mc 与 windows-amd64/mc.exe
minio sdk: https://dl.min.io/sdk/minio-java/

官方文档:MinIO Client (mc) — MinIO祼机使用文档

MinIO Server — MinIO祼机使用文档

二、使用说明

1.使用体验

单机部署简单,使用一条指令即可启动、配置服务器节点(服务器地址,端口、api端口)minio服务,自带页面。
mc客户端有详细中文文档,api调用接口简易

支持生命周期管理(支持日期与天数、支持设置桶内文件夹),设置后,文件会根据规则自动删除源文件

2.大体工作流程

minioServer部署—>mc客户端/api接口创建存储---->mc客户端/api接口配置生命周期规则—>minio页面/api接口存储文件—>minio页面/api接口获取文件或文件url

三、minio Server部署

1.启动服务

linux:

./minio server /data/minio  --address ip:api调用端口  --console-address ip:服务器端口 --config-dir 配置文件地址

window:

.\minio.exe server D:\Utils\minio\  --address ip:api调用端口  --console-address ip:服务器端口 --config-dir 配置文件地址

在这里插入图片描述
在这里插入图片描述

2.配置

minIO server在默认情况下会将所有配置信息存到 ${HOME}/.minio/config.json 文件中。 可用--config-dir在启动服务时重写

# 设置用户名
set MINIO_ACCESS_KEY=minioadmin
# 设置密码(8位)
set MINIO_SECRET_KEY=minioadmin
3.证书目录

TLS证书存在${HOME}/.minio/certs目录下,你需要将证书放在该目录下来启用HTTPS 。如果你是一个乐学上进的好青年,这里有一本免费的秘籍传授一你: 如何使用TLS安全的访问minio.

以下是一个带来TLS证书的MinIO server的目录结构。

Copy$ tree ~/.minio
/home/user1/.minio
├── certs
│   ├── CAs
│   ├── private.key
│   └── public.crt
└── config.json

四、MinIO Client使用

MinIO Client 简称mc,是minio服务器的客户端,对ls,cat,cp,mirror,diff,find等UNIX命令提供了一种替代方案,它支持文件系统和兼容Amazon S3的云存储服务(AWS Signature v2和v4)。

1.mc指令

ls 列出文件和文件夹。
mb 创建一个存储桶或一个文件夹。
cat 显示文件和对象内容。
pipe 将一个STDIN重定向到一个对象或者文件或者STDOUT。
share 生成用于共享的URL。
cp 拷贝文件和对象。
mirror 给存储桶和文件夹做镜像。
find 基于参数查找文件。
diff 对两个文件夹或者存储桶比较差异。
rm 删除文件和对象。
events 管理对象通知。
watch 监听文件和对象的事件。
policy 管理访问策略。
session 为cp命令管理保存的会话。
config 管理mc配置文件。
update 检查软件更新。
version 输出版本信息。

2.常用命令
//设置        别名  api地址	用户名      密码
mc alias set ALIAS HOSTNAME ACCESSKEY SECRETKEY 
//列出指定桶的当前生命周期管理规则
mc ilm list TARGET [FLAGS]

//添加新的存储桶生命周期管理规则
mc ilm add TARGET [FLAGS]
// 使用 mc ilm add 和 --expiry-days 到 在对象创建数天后使存储桶内容过期:
mc ilm add ALIAS/PATH --expiry-days "DAYS"
//使用 mc ilm remove 删除存储桶生命周期管理规则 
mc ilm remove --id "RULE" ALIAS/PATH

五、MINIO SDK(Java) Java Client API参考文档 | Minio中文文档

1.导入
<!--maven-->
            <dependency>
                <groupId>io.minio</groupId>
                <artifactId>minio</artifactId>
                <version>8.4.1</version>
                <exclusions>
                    <exclusion>
                        <groupId>com.squareup.okhttp3</groupId>
                        <artifactId>okhttp</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
<!--minio的okhttp有可能会报错-->
            <dependency>
                <groupId>com.squareup.okhttp3</groupId>
                <artifactId>okhttp</artifactId>
                <version>4.9.0</version>
            </dependency>
        </dependencies>
<!--gradle-->
dependencies {
    compile 'io.minio:minio:8.4.1'
}
2.配置
#minio
minio:
  url: http://10.10.18.178:9000
  accessKey: minioadmin
  secretKey: minioadmin
  bucketName: bucket-test01
  #分区上传文件大小
  partSize: 104857600
import cn.akeparking.middleware.service.minio.MinioTemplate;
import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author qiukl
 * @create 2022/5/24 17:51
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinIoConfig {
    /**
     * 服务地址(服务接口地址)
     */
    private String url;
    /**
     * 用户名
     */
    private String accessKey;
    /**
     * 密码
     */
    private String secretKey;
    /**
     * 存储桶名称
     */
    private String bucketName;
    private Integer partSize;
    @Bean
    public MinioTemplate getMinioClient() {
        return new MinioTemplate(url,accessKey, secretKey,partSize);
    }
}
3.常用api
1)创建储存桶

通过MinioTemplate.createBucket(bucketName)创建桶,或调用sdk包的minioClient.makeBucket方法

2)设置生命周期

通过MinioTemplate.setBucketExpirationByDays(bucketName,prefix,days,ruleName)创建对应桶的生命周期,prefix对应相应的文件夹,days对应过期天数,ruleName对应文件名称

3)存入文件

通过MinioTemplate.putObject(bucketName,objectName,base64Str/MultipartFile/InputStream)存入文件,实际上皆转为上传

PutObjectArgs putObjectArgs = PutObjectArgs.builder()
        .bucket(bucketName)
        .object(objectName)
        .stream(stream, size, partSize)
        .build();
client.putObject(putObjectArgs);

4)取文件

通过MinioTemplate.getObject(bucketName,objectName)获取对应的文件流,或者通过MinioTemplate.presignedObjectUrl(bucketName,objectName,时间, 时间单位)来获取有期限的文件url

4.工具类
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.*;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * @author qiukl
 * @create 2022/5/24 17:40
 */
@AllArgsConstructor
@Slf4j
public class MinioTemplate {

    private String endpoint;
    private String accessKey;
    private String secretKey;
    private int partSize;

    private MinioClient client;

    @SneakyThrows
    public MinioTemplate(String endpoint, String accessKey, String secretKey, int partSize) {
        this.endpoint = endpoint;
        this.accessKey = accessKey;
        this.secretKey = secretKey;
        this.partSize = partSize;
        this.client = MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();

    }

    /**
     * 创建bucket
     *
     * @param bucketName bucket名称
     */
    public void createBucket(String bucketName) throws Exception {
        if (!client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
            client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     *
     * @param bucketName
     * @param days
     * @param ruleName
     * @throws Exception
     */
    public void setBucketExpirationByDays(String bucketName,String prefix,Integer days,String ruleName) throws Exception{
        // 获取配置
        LifecycleConfiguration lifecycleConfiguration =
                client.getBucketLifecycle(
                        GetBucketLifecycleArgs
                                .builder()
                                .bucket(bucketName)
                                .build());
        List<LifecycleRule> rules = lifecycleConfiguration.rules();

        List<LifecycleRule> rulesNew = new ArrayList<>();
        rulesNew.addAll(rules);
        // 配置生命周期规则
        rulesNew.add(
                new LifecycleRule(
                        Status.ENABLED, // 开启状态
                        null,
                        new Expiration((ZonedDateTime) null, days, null), // 保存365天
                        new RuleFilter(prefix), // 目录配置
                        ruleName,
                        null,
                        null,
                        null)
        );
        LifecycleConfiguration lifecycleConfigurationNew = new LifecycleConfiguration(rulesNew);
        // 添加生命周期配置
        client.setBucketLifecycle(
                SetBucketLifecycleArgs
                        .builder()
                        .bucket(bucketName)
                        .config(lifecycleConfigurationNew)
                        .build()
        );
    }

    public List<LifecycleRule> getBucketLifecycleRule(String bucketName) throws Exception{
        // 获取配置
        LifecycleConfiguration lifecycleConfiguration1111 =
                client.getBucketLifecycle(
                        GetBucketLifecycleArgs
                                .builder()
                                .bucket(bucketName)
                                .build());
        List<LifecycleRule> rules1 = lifecycleConfiguration1111.rules();
        for (LifecycleRule lifecycleRule:rules1) {
            log.debug(lifecycleRule.toString());
            log.debug("Lifecycle status is " + lifecycleRule.status()
                    +"\nLifecycle prefix is " + lifecycleRule.filter().prefix()
                    +"\nLifecycle expiration days is " + lifecycleRule.expiration().days());
        }
        return rules1;
    }


    /**
     * 获取全部bucket
     * <p>
     * https://docs.minio.io/cn/java-client-api-reference.html#listBuckets
     */
    public List<Bucket> getAllBuckets() throws Exception {
        return client.listBuckets();
    }

    /**
     * 根据bucketName获取信息
     * @param bucketName bucket名称
     */
    public Optional<Bucket> getBucket(String bucketName) throws Exception {
        return client.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
    }

    /**
     * 根据bucketName删除信息
     * @param bucketName bucket名称
     */
    public void removeBucket(String bucketName) throws Exception {
        client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
    }

    /**
     * 分区上传文件
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param stream 文件流
     * @param size 文件大小
     */
    public String putObject(String bucketName, String objectName, InputStream stream, Long size) throws Exception{
        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .stream(stream, size, partSize)
                .build();
        ObjectWriteResponse objectWriteResponse = client.putObject(putObjectArgs);
        return objectWriteResponse.object();
    }

    /**
     * 根据文件前置查询文件
     *
     * @param bucketName bucket名称
     * @param prefix     前缀
     * @param recursive  是否递归查询
     * @return MinioItem 列表
     */
    public List<Item> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) throws Exception {
        List<Item> objectList = new ArrayList<>();
        ListObjectsArgs listObjectsArgs = ListObjectsArgs.builder()
                .bucket(bucketName)
                .prefix(prefix)
                .recursive(recursive)
                .build();

        Iterable<Result<Item>> objectsIterator = client
                .listObjects(listObjectsArgs);

        while (objectsIterator.iterator().hasNext()) {
            objectList.add(objectsIterator.iterator().next().get());
        }
        return objectList;
    }

    /**
     * 获取文件外链
     * 这里的 method 方法决定最后链接是什么请求获得
     *  expiry 决定这个链接多久失效
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param duration 有效大小
     * @param
     * @return url
     */
    public String getObjectURL(String bucketName, String objectName,Integer duration, TimeUnit unit) throws Exception {
        if (null==duration||null==unit){
            duration = 7;
            unit = TimeUnit.DAYS;
        }
        GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                .bucket(bucketName)
                .method(Method.GET)
                .expiry(duration, unit)
                .object(objectName)
                .build();

        return client.getPresignedObjectUrl(args);
    }

    /**
     * 获取文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return 二进制流
     */
    public InputStream getObject(String bucketName, String objectName) throws Exception {
        GetObjectArgs getObjectArgs = GetObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build();
        return client.getObject(getObjectArgs);
    }


    /**
     * 上传文件 base64
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param base64Str 文件base64
     */
    public String putObject(String bucketName, String objectName, String base64Str) throws Exception{
        InputStream inputStream = new ByteArrayInputStream(base64Str.getBytes());
        // 进行解码
        BASE64Decoder base64Decoder = new BASE64Decoder();
        byte[] byt = new byte[0];
        try {
            byt = base64Decoder.decodeBuffer(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        inputStream = new ByteArrayInputStream(byt);
        putObject(bucketName, objectName, inputStream, Long.valueOf(byt.length));
        return objectName;
    }

    /**
     * 上传文件
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param file 文件
     * @throws Exception
     */
    public String putObject( String bucketName,String objectName, MultipartFile file) throws Exception{
        this.putObject(bucketName, objectName, file.getInputStream(), file.getSize());
        return objectName;
    }

    /**
     * 获取文件信息
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#statObject
     */
    public StatObjectResponse getObjectInfo(String bucketName, String objectName) throws Exception {
        StatObjectArgs statObjectArgs = StatObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build();
        return client.statObject(statObjectArgs);
    }

    /**
     * 删除文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#removeObject
     */
    public void removeObject(String bucketName, String objectName) throws Exception {
        RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build();
        client.removeObject(removeObjectArgs);
    }

    /**
     * 根据文件名返回对应contentType
     * @param objectName
     * @return
     */
    private String getContentType(String objectName) {
        //if(FileNameUtil.isPicture(objectName)) {
        //    return "image/jpeg";
        //}
        //if(FileNameUtil.isVideo(objectName)) {
        //    return "video/mp4";
        //}
        return null;
    }

    /**
     * 获取直传链接
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @throws Exception
     */
    public String presignedPutObject( String bucketName,String objectName) throws Exception{
        GetPresignedObjectUrlArgs getPresignedObjectUrlArgs = GetPresignedObjectUrlArgs.builder()
                .method(Method.PUT)
                .bucket(bucketName)
                .object(objectName)
                .expiry(7, TimeUnit.DAYS)
                .build();
        return client.getPresignedObjectUrl(getPresignedObjectUrlArgs);
    }

    /**
     * 合并文件
     * @param bucketName
     * @param chunkNames
     * @param targetObjectName
     * @return
     * @throws Exception
     */
    public String composeObject(String bucketName, List<String> chunkNames, String targetObjectName) throws Exception{
        List<ComposeSource> sources = new ArrayList<>(chunkNames.size());
        for (String chunkName : chunkNames) {
            ComposeSource composeSource = ComposeSource.builder()
                    .bucket(bucketName)
                    .object(chunkName)
                    .build();
            sources.add(composeSource);
        }
        ComposeObjectArgs composeObjectArgs = ComposeObjectArgs.builder()
                .bucket(bucketName)
                .sources(sources)
                .object(targetObjectName)
                .build();
        ObjectWriteResponse objectWriteResponse = client.composeObject(composeObjectArgs);
        return objectWriteResponse.object();
    }
}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐