• 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);
            }
        }
    }
    
  • 相关阅读:
    Linux 共享库
    使用Visual Studio(VS)开发Qt程序代码提示功能的实现(转)
    ZOJ 3469 Food Delivery(区间DP)
    POJ 2955 Brackets (区间DP)
    HDU 3555 Bomb(数位DP)
    HDU 2089 不要62(数位DP)
    UESTC 1307 windy数(数位DP)
    HDU 4352 XHXJ's LIS(数位DP)
    POJ 3252 Round Numbers(数位DP)
    HDU 2476 String painter (区间DP)
  • 原文地址:https://www.cnblogs.com/seliote/p/14828822.html
Copyright © 2020-2023  润新知