您现在的位置是:首页 >技术交流 >Spring项目整合Minio分布式的对象存储系统网站首页技术交流

Spring项目整合Minio分布式的对象存储系统

carroll18 2023-05-22 16:00:02
简介Spring项目整合Minio分布式的对象存储系统

安装

Docker安装

docker run -p 9000:9000 -p 9090:9090 
     --net=host 
     --name minio 
     -d --restart=always 
     -e "MINIO_ACCESS_KEY=admin" 
     -e "MINIO_SECRET_KEY=123456" 
     -v /usr/local/minio/data:/data 
     minio/minio server 
     /data --console-address ":9090" -address ":9000"

Docker-compose安装

version: '3'
services:
  minio:
    image: minio/minio
    restart: always
    environment:
      - MINIO_ACCESS_KEY=admin
      - MINIO_SECRET_KEY=123456
    command: server /data --console-address ":9090" -address ":9000"
    container_name: minio
    hostname: minio
    volumes:
      - /usr/local/minio/data:/data
    logging:
      driver: json-file
      options:
        max-size: '20m'
        max-file: '20'
    network_mode: host

SpringBoot集成

引入依赖

<dependency>
	<groupId>io.minio</groupId>
	<artifactId>minio</artifactId>
	<version>8.3.7</version>
</dependency>
     <dependency>
     <groupId>com.squareup.okhttp3</groupId>
     <artifactId>okhttp</artifactId>
     <version>4.8.1</version>
</dependency>

初始化客户端

@Component
@ConfigurationProperties(prefix = "minio")
@Slf4j
public class MinioService implements InitializingBean {

    /**
     * MinIO的API地址
     */
    @Setter
    private String endpoint;

    /**
     * 用户名
     */
    @Setter
    private String accessKey;

    /**
     * 密钥
     */
    @Setter
    private String secretKey;

    /**
     * 自定义域名(非必须)
     */
    @Setter
    private String customDomain;

    /**
     * 存储桶名称,默认微服务单独一个存储桶
     */
    @Setter
    private String defaultBucket;

    private MinioClient minioClient;

	// 初始化客户端
    @Override
    public void afterPropertiesSet() {
        log.info("初始化 MinIO 客户端...");
        Assert.notBlank(endpoint, "MinIO endpoint不能为空");
        Assert.notBlank(accessKey, "MinIO accessKey不能为空");
        Assert.notBlank(secretKey, "MinIO secretKey不能为空");
        this.minioClient = MinioClient.builder()
                //.endpoint(endpoint, 443, true)
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();
    }
}

存储桶的CRUD

存储桶是否存在

public boolean bucketExists(BucketExistsArgs args);

创建存储桶

 /**
     * 创建存储桶(存储桶不存在)
     *
     * @param bucketName
     */
    @SneakyThrows
    public void createBucketIfAbsent(String bucketName) {
        BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder()
                .bucket(bucketName)
                .build();
        if (!minioClient.bucketExists(bucketExistsArgs)) {
            MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build();

            minioClient.makeBucket(makeBucketArgs);

            // 设置存储桶访问权限为PUBLIC, 如果不配置,则新建的存储桶默认是PRIVATE,则存储桶文件会拒绝访问 Access Denied
            SetBucketPolicyArgs setBucketPolicyArgs = SetBucketPolicyArgs.builder()
                    .bucket(bucketName)
                    .config(publicBucketPolicy(bucketName).toString())
                    .build();
            minioClient.setBucketPolicy(setBucketPolicyArgs);
        }
    }


    /**
     * PUBLIC桶策略
     * 如果不配置,则新建的存储桶默认是PRIVATE,则存储桶文件会拒绝访问 Access Denied
     *
     * @param bucketName
     * @return
     */
    private static StringBuilder publicBucketPolicy(String bucketName) {
        /**
         * AWS的S3存储桶策略
         * Principal: 生效用户对象
         * Resource:  指定存储桶
         * Action: 操作行为
         */
        StringBuilder builder = new StringBuilder();
        builder.append("{"Version":"2012-10-17"," +
                ""Statement":[{"Effect":"Allow"," +
                ""Principal":{"AWS":["*"]}," +
                ""Action":["s3:ListBucketMultipartUploads","s3:GetBucketLocation","s3:ListBucket"]," +
                ""Resource":["arn:aws:s3:::" + bucketName + ""]}," +
                "{"Effect":"Allow"," +
                ""Principal":{"AWS":["*"]}," +
                ""Action":["s3:ListMultipartUploadParts","s3:PutObject","s3:AbortMultipartUpload","s3:DeleteObject","s3:GetObject"]," +
                ""Resource":["arn:aws:s3:::" + bucketName + "/*"]}]}");

        return builder;
    }

查询存储桶信息列表

public List<Bucket> listBuckets();

删除一个空桶

public void removeBucket(RemoveBucketArgs args) 

存储桶的文件操作


   

    /**
     * 上传文件对象(默认存储桶)
     *
     * @param file MultipartFile文件对象
     * @return
     */
    public String putObject(MultipartFile file) {
        String fileUrl = putObject(file, defaultBucket);
        return fileUrl;
    }

    /**
     * 上传文件对象
     *
     * @param file       MultipartFile文件对象
     * @param bucketName 存储桶名称
     * @return
     */
    @SneakyThrows
    public String putObject(MultipartFile file, String bucketName) {
        // 存储桶名称为空则使用默认的存储桶
        if (StrUtil.isBlank(bucketName)) {
            bucketName = defaultBucket;
        }

        createBucketIfAbsent(bucketName);

        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
        String fileName = IdUtil.simpleUUID() + "." + suffix;

        InputStream inputStream = file.getInputStream();
        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .bucket(bucketName)
                .object(fileName)
                .contentType(file.getContentType())
                .stream(inputStream, inputStream.available(), -1)
                .build();

        minioClient.putObject(putObjectArgs);

        String fileUrl;
        if (StrUtil.isBlank(customDomain)) { // 没有自定义文件路径域名
            GetPresignedObjectUrlArgs getPresignedObjectUrlArgs = GetPresignedObjectUrlArgs.builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .method(Method.GET)
                    .build();

            fileUrl = minioClient.getPresignedObjectUrl(getPresignedObjectUrlArgs);
            fileUrl = fileUrl.substring(0, fileUrl.indexOf("?"));
        } else { // 自定义文件路径域名,Nginx配置方向代理转发MinIO
            fileUrl = customDomain +'/'+ bucketName + "/" + fileName;
        }
        return fileUrl;
    }

    public void removeObject(String bucket, String fileName) throws Exception {
        RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder()
                .bucket(bucket)
                .object(fileName)
                .build();
        minioClient.removeObject(removeObjectArgs);
    }

存储桶生命周期配置


    /*
     * oss设置生命周期规则
     * 存储桶生命周期配置:  public void setBucketLifecycle(SetBucketLifecycleArgs args)
     * 获取桶的生命周期配置: public LifecycleConfiguration getBucketLifecycle(GetBucketLifecycleArgs args)
     *
     * */
    @SneakyThrows
    public void setBucketLifecycle(String bucketName, String ruleId, String prefix, Integer days ) {
        List<LifecycleRule> rules = new LinkedList<>();
        rules.add(
                new LifecycleRule(
                        Status.ENABLED,
                        null,
                        new Expiration((ZonedDateTime) null, days, null),
                        new RuleFilter(prefix),
                        ruleId,
                        null,
                        null,
                        null));
        LifecycleConfiguration config = new LifecycleConfiguration(rules);
        minioClient.setBucketLifecycle(
                SetBucketLifecycleArgs.builder().bucket(bucketName).config(config).build());
    }

在这里插入图片描述

  • oss设置生命周期规则
    • 存储桶生命周期配置: public void setBucketLifecycle(SetBucketLifecycleArgs args)
    • 获取桶的生命周期配置: public LifecycleConfiguration getBucketLifecycle(GetBucketLifecycleArgs args)
  • LifecycleRule 的配置参数
    • status:设置规则开启还是关闭状态。
    • AbortIncompleteMultipartUpload(int daysAfterInitiation):设置分片在距最后修改时间30天后过期。
    • Expiration(ZonedDateTime date, Integer days, Boolean expiredObjectDeleteMarker) :指定日期天数过期标志删除or彻底删除
    • RuleFilter(AndOperator andOperator,String prefix,Tag tag) :依据前缀删除(前缀即桶内的文件夹名)或者 tag标志删除
    • id,一个桶可以设置多个rule
    • NoncurrentVersionExpiration(int noncurrentDays):设置非当前版本的Object
    • NoncurrentVersionTransition(int noncurrentDays,String storageClass): 设置非当前版本的Object距最后修改时间90天之后转为低频访问类型、归档类型。非当前版本对象何时进行存储类型的转换和转换的存储类型,待确认storageClass

你知道的越多,你不知道的越多。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。