zoukankan      html  css  js  c++  java
  • Java 集成 MinIO

    完整的项目在 GitHub-mlb

    配置类

    package com.seliote.mlb.fs.config;
    
    import com.seliote.mlb.common.config.PropertiesInjector;
    import io.minio.BucketExistsArgs;
    import io.minio.MinioClient;
    import io.minio.errors.MinioException;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.io.IOException;
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    
    /**
     * MinIO 配置类
     *
     * @author seliote
     */
    @Slf4j
    @Configuration
    public class MinioConfig {
    
        private final PropertiesInjector.Minio minioProp;
    
        @Autowired
        public MinioConfig(PropertiesInjector propertiesInjector) {
            this.minioProp = propertiesInjector.getMinio();
        }
    
        /**
         * MinioClient Bean
         *
         * @return MinioClient 对象
         */
        @Bean
        public MinioClient minioClient()
                throws MinioException, IOException, NoSuchAlgorithmException, InvalidKeyException {
            var client = MinioClient.builder()
                    .endpoint(minioProp.getEndpoint())
                    .credentials(minioProp.getAccessKey(), minioProp.getSecretKey())
                    .build();
            // 检查 Bucket 是否存在
            boolean found = client.bucketExists(BucketExistsArgs.builder()
                    .bucket(minioProp.getBucket())
                    .build());
            if (!found) {
                log.error("Bucket {} not found! Please create it first", minioProp.getBucket());
                throw new IllegalStateException("Bucket not found");
            }
            log.info("Minio bucket: {}", minioProp.getBucket());
            return client;
        }
    }
    

    Service

    package com.seliote.mlb.fs.service;
    
    import com.seliote.mlb.common.jsr303.MinioBucket;
    import org.springframework.validation.annotation.Validated;
    
    import javax.validation.constraints.NotBlank;
    import javax.validation.constraints.NotNull;
    import java.io.IOException;
    import java.io.InputStream;
    
    /**
     * 文件 Service
     *
     * @author seliote
     */
    @Validated
    public interface FileService {
    
        // 图片分类名称
        String IMG = "img";
        // 音频分类名称
        String AUDIO = "audio";
    
        /**
         * 上传文件到指定目录
         * <em>操作完成后不会关闭流, 需调用者来关闭</em>
         * <em>未正确关闭流会导致句柄泄漏</em>
         *
         * @param catalog       分类
         * @param fileExtension 文件扩展名, 如 mp3, jpg
         * @param inputStream   输入流
         * @return Minio 文件名, 后续需使用此文件名下载文件
         */
        String upload(@MinioBucket String catalog,
                      @NotBlank String fileExtension,
                      @NotNull InputStream inputStream) throws IOException;
    
        /**
         * 下载指定文件
         * <em>需调用方关闭返回的流</em>
         * <em>未正确关闭流会导致句柄泄漏</em>
         *
         * @param catalog  分类
         * @param filename 文件名称
         */
        InputStream download(@MinioBucket String catalog, @NotBlank String filename) throws IOException;
    }
    

    Impl

    package com.seliote.mlb.fs.service.impl;
    
    import com.seliote.mlb.common.config.PropertiesInjector;
    import com.seliote.mlb.fs.service.FileService;
    import io.minio.GetObjectArgs;
    import io.minio.MinioClient;
    import io.minio.PutObjectArgs;
    import io.minio.errors.MinioException;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    import java.util.UUID;
    
    /**
     * 文件 Service 实现
     *
     * @author seliote
     */
    @Slf4j
    @Service
    public class FileServiceImpl implements FileService {
    
        // Minio 文件的分隔符
        private final String FS_SEPARATOR = "/";
    
        private final PropertiesInjector.Minio minioProp;
        private final MinioClient minioClient;
    
        @Autowired
        public FileServiceImpl(PropertiesInjector propertiesInjector,
                               MinioClient minioClient) {
            this.minioProp = propertiesInjector.getMinio();
            this.minioClient = minioClient;
        }
    
        @Override
        public String upload(String catalog, String fileExtension, InputStream inputStream) throws IOException {
            // 生成随机 UUID 作为应用名称
            String filename = UUID.randomUUID().toString();
            // 将文件放在不同目录
            // Minio 会默认放在同一文件夹下, 手动分开为 36 * 36, 避免同一文件夹下文件数量过多影响 IO
            filename = filename.charAt(0) + FS_SEPARATOR
                    + filename.charAt(1) + FS_SEPARATOR
                    + filename + "." + fileExtension;
            try {
                minioClient.putObject(PutObjectArgs.builder()
                        .bucket(minioProp.getBucket())
                        .object(String.format("%s%s%s", catalog, FS_SEPARATOR, filename))
                        .stream(inputStream, -1, 1024 * 1024 * 10)
                        .build());
                log.info("Upload {} {} success", catalog, filename);
            } catch (MinioException | InvalidKeyException | NoSuchAlgorithmException e) {
                log.error("Upload {} {} failed, {}, message: {}",
                        catalog, filename, e.getClass().getCanonicalName(), e.getMessage());
                throw new IOException(e);
            }
            return filename;
        }
    
        @Override
        public InputStream download(String catalog, String filename) throws IOException {
            try {
                var getObjectResponse = minioClient.getObject(GetObjectArgs.builder()
                        .bucket(minioProp.getBucket())
                        .object(String.format("%s%s%s", catalog, FS_SEPARATOR, filename))
                        .build());
                log.info("Download {} {} success", catalog, filename);
                return getObjectResponse;
            } catch (MinioException | InvalidKeyException | IOException | NoSuchAlgorithmException e) {
                log.error("Download {} {} failed, {}, message: {}",
                        catalog, filename, e.getClass().getCanonicalName(), e.getMessage());
                throw new IOException(e);
            }
        }
    }
    
  • 相关阅读:
    flex布局
    媒体查询
    transform详细解释
    读取long类型数据
    Oracle中快速清空当前用户的所有表数据
    没有表头的csv文件怎么导入Kettle
    Kettle性能调优汇总
    oralce中特殊字符的查询
    数据的单值、多值、派生、简单、复合属性
    kettle学习
  • 原文地址:https://www.cnblogs.com/seliote/p/14828822.html
Copyright © 2011-2022 走看看