侧边栏壁纸
  • 累计撰写 41 篇文章
  • 累计创建 34 个标签
  • 累计收到 0 条评论
隐藏侧边栏

SpringBoot接入MinIo

LonelySmile
2024-03-16 / 0 评论 / 0 点赞 / 78 阅读 / 11,996 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2024-03-16,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

SpringBoot接入MinIo

  1. 添加pom.xml依赖

    <dependency>
        <groupId>io.minio</groupId>
        <artifactId>minio</artifactId>
        <version>8.3.3</version>
    </dependency>
    
  2. 配置yml参数

    # MinIO 对象存储配置
    minio:
      # 是否开启
      enabled: true
      # 服务地址
      url: http://192.168.1.139:7101
      # 账号
      access: archive
      # 密钥
      secret: jiyang123!@#
      # 存储桶名称
      bucket: files
    
  3. 客户端初始化配置

    import io.minio.BucketExistsArgs;
    import io.minio.MakeBucketArgs;
    import io.minio.MinioClient;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * MinIO对象存储配置类
     *
     * @author wujie
     * @version 1.0
     */
    @ConditionalOnProperty(name = "minio.enabled", havingValue = "false")
    @Configuration
    public class MinioConfig {
    
        private static final Logger log = LoggerFactory.getLogger(MinioConfig.class);
    
        @Value("${minio.url}")
        private String url;
        @Value("${minio.access}")
        private String access;
        @Value("${minio.secret}")
        private String secret;
        @Value("${minio.bucket}")
        private String bucket;
    
        /**
         * MinIO对象存储系统配置
         *
         * @return {@link MinioClient}
         */
        @Bean
        public MinioClient minioClient() {
            log.info("-----------MinIO对象存储初始化加载-----------");
            log.info("{}-----{}------{}", url, access, bucket);
            MinioClient minioClient = null;
            try {
                minioClient = MinioClient.builder().endpoint(url).credentials(access, secret).build();
                // 判断Bucket是否存在
                boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
                if (!exists) {
                    // 不存在则创建一个新的Bucket
                    minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
                    log.info("-----------MinIO对象存储Bucket[{}]已创建-----------", bucket);
                }
                log.info("-----------MinIO对象存储初始化完成-----------");
            } catch (Exception e) {
                log.error("MinIO对象存储初始化失败,{}", e.getMessage());
            }
            return minioClient;
        }
    }
    
  4. 工具类

    import com.jiyang.common.exception.CustomException;
    import io.minio.*;
    import io.minio.http.Method;
    import io.minio.messages.DeleteError;
    import io.minio.messages.DeleteObject;
    import io.minio.messages.Item;
    import org.apache.commons.io.IOUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.http.MediaType;
    import org.springframework.http.MediaTypeFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.multipart.MultipartFile;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.*;
    import java.util.concurrent.TimeUnit;
    
    /**
     * MinIO对象存储工具类
     *
     * @author wujie
     * @version 1.0
     */
    @ConditionalOnProperty(name = "minio.enabled", havingValue = "false")
    @Component
    public class MinioUtils {
    
        private static final Logger log = LoggerFactory.getLogger(MinioUtils.class);
    
        @Value("${minio.bucket}")
        private String bucket;
    
        private final MinioClient minioClient;
    
        @Autowired(required = false)
        public MinioUtils(MinioClient minioClient) {
            this.minioClient = minioClient;
        }
    
        /**
         * 获取日期字符串,用分隔符模拟文件夹路径
         */
        private static final String NOW = DateUtils.parseDateToStr("yyyy/MM/dd/", new Date());
    
    
        /**
         * 文件对象上传
         *
         * @param file 文件对象
         * @return 存储的文件名和路径
         */
        public String putObject(MultipartFile file) {
            try {
                return putObject(file.getInputStream(), file.getResource().getFilename(), file.getContentType());
            } catch (IOException e) {
                throw new CustomException("MinIO文件上传失败," + e.getMessage());
            }
        }
    
        /**
         * 文件流存储
         * <p>
         * 添加的Object大小不能超过 5GB。
         * 默认情况下,如果已存在同名Object且对该Object有访问权限,则新添加的Object将覆盖原有的Object
         * OSS没有文件夹的概念,所有资源都是以文件来存储,但您可以通过创建一个以正斜线(/)结尾,大小为 0的Object来创建模拟文件夹(指定 /后,默认会自动创建)
         *
         * @param is          文件流
         * @param fileName    文件名称
         * @param contentType 文件类型
         * @return 存储的文件名和路径
         */
        public String putObject(InputStream is, String fileName, String contentType) {
            try {
                String name = NOW + fileName;
                minioClient.putObject(
                        PutObjectArgs.builder().bucket(bucket).object(name).stream(
                                        is, is.available(), -1)
                                .contentType(contentType)
                                .build()
                );
                log.info("MinIO文件[{}]存储成功", name);
                return name;
            } catch (Exception e) {
                throw new CustomException("MinIO文件存储失败," + e.getMessage());
            } finally {
                IOUtils.closeQuietly(is);
            }
        }
    
        /**
         * 本地磁盘文件存储
         *
         * @param objectName 对象名称
         * @param fileName   文件名,带磁盘路径
         * @return 存储的文件名和路径
         */
        public String uploadObject(String objectName, String fileName) {
            try {
                String name = NOW + objectName;
                String content = MediaTypeFactory.getMediaType(fileName).orElse(MediaType.APPLICATION_OCTET_STREAM).toString();
                minioClient.uploadObject(
                        UploadObjectArgs.builder().bucket(bucket)
                                .object(name).
                                filename(fileName).contentType(content).build()
                );
                log.info("MinIO文件[{}]存储成功", name);
                return name;
            } catch (Exception e) {
                throw new CustomException("MinIO文件存储失败," + e.getMessage());
            }
        }
    
        /**
         * 获取文件对象
         * <p>
         * 返回结果是 GetObjectResponse类,它继承了 InputStream类
         * GetObjectResponse使用后返回必须关闭以释放网络资源
         * 此操作需要对此Object具有读权限
         *
         * @param fileName 文件名
         * @return 字节数组
         */
        public byte[] getObject(String fileName) {
            try (InputStream stream = minioClient.getObject(
                    GetObjectArgs.builder()
                            .bucket(bucket)
                            .object(fileName)
                            .build())) {
                return IOUtils.toByteArray(stream);
            } catch (Exception e) {
                throw new CustomException("MinIO文件获取失败");
            }
        }
    
        /**
         * 文件下载
         * <p>
         * 将对象的数据下载到磁盘
         *
         * @param objectName 对象名称
         * @param fileName   存储的磁盘文件路径
         */
        public void downloadObject(String objectName, String fileName) {
            try {
                minioClient.downloadObject(
                        DownloadObjectArgs.builder()
                                .bucket(bucket)
                                .object(objectName)
                                .filename(fileName)
                                .build());
                log.info("MinIO文件[{} --> {}]下载成功", objectName, fileName);
            } catch (Exception e) {
                throw new CustomException("MinIO文件下载失败");
            }
        }
    
        /**
         * 获取 HTTP 方法、到期时间和自定义请求参数的对象的预签名 URL
         *
         * @param method      请求方式
         * @param objectName  对象名称
         * @param duration    期限
         * @param unit        时间单位
         * @param contentType 内容类型
         * @return 预签名URL
         */
        public String createPresignedObjectUrl(Method method, String objectName, int duration, TimeUnit unit, String contentType) {
            Map<String, String> reqParams = new HashMap<>(1);
            reqParams.put("response-content-type", contentType);
            try {
                return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                        .method(method)
                        .bucket(bucket)
                        .object(objectName)
                        .expiry(duration, unit)
                        .extraQueryParams(reqParams)
                        .build());
            } catch (Exception e) {
                throw new CustomException("Presigned URL生成失败," + e.getMessage());
            }
        }
    
        /**
         * 生成一个给HTTP GET请求用的presigned URL。
         * <p>
         * 浏览器/移动端的客户端可以用这个URL进行下载,即使其所在的存储桶是私有的。
         * 这个presigned URL可以设置一个失效时间,默认值是7天。
         * 使用此方法,可以提供给不用登录进行图片浏览,第三方共享访问等。
         *
         * @param objectName  对象名称
         * @param contentType 内容类型
         * @return 预签名URL
         */
        public String presignedGetObject(String objectName, String contentType) {
            return defaultExpiryParams(Method.GET, objectName, contentType);
        }
    
        /**
         * 默认设置过期时间为7天
         *
         * @param method      请求方式
         * @param objectName  对象名称
         * @param contentType 内容类型
         * @return 预签名URL
         */
        private String defaultExpiryParams(Method method, String objectName, String contentType) {
            return createPresignedObjectUrl(method, objectName, 7, TimeUnit.DAYS, contentType);
        }
    
        /**
         * 生成一个给HTTP GET请求用的presigned URL。
         * <p>
         * 浏览器/移动端的客户端可以用这个URL进行下载
         * 使用此方法,可以提供给不用登录进行图片浏览,第三方共享访问等。
         *
         * @param objectName  对象名称
         * @param duration    期限
         * @param unit        时间单位
         * @param contentType 内容类型
         * @return 预签名URL
         */
        public String presignedGetObject(String objectName, int duration, TimeUnit unit, String contentType) {
            return createPresignedObjectUrl(Method.GET, objectName, duration, unit, contentType);
        }
    
        /**
         * 生成一个给HTTP PUT请求用的presigned URL。
         * <p>
         * 浏览器/移动端的客户端可以用这个URL进行上传,即使其所在的存储桶是私有的
         * 这个presigned URL可以设置一个失效时间,默认值是7天
         *
         * @param objectName  对象名称
         * @param contentType 内容类型
         * @return 预签名URL
         */
        public String presignedPutObject(String objectName, String contentType) {
            return defaultExpiryParams(Method.PUT, objectName, contentType);
        }
    
        /**
         * 生成一个给HTTP PUT请求用的presigned URL。
         * <p>
         * 浏览器/移动端的客户端可以用这个URL进行上传,即使其所在的存储桶是私有的
         *
         * @param objectName  对象名称
         * @param duration    期限
         * @param unit        时间单位
         * @param contentType 内容类型
         * @return 预签名URL
         */
        public String presignedPutObject(String objectName, int duration, TimeUnit unit, String contentType) {
            return createPresignedObjectUrl(Method.PUT, objectName, duration, unit, contentType);
        }
    
        /**
         * 删除文件对象
         *
         * @param objectName 对象名称
         */
        public void removeObject(String objectName) {
            try {
                minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucket).object(objectName).build());
                log.info("MinIO文件[{}]删除成功", objectName);
            } catch (Exception e) {
                throw new CustomException("MinIO文件[" + objectName + "]删除失败," + e.getMessage());
            }
        }
    
        /**
         * 批量删除文件对象
         *
         * @param objects 文件集合
         */
        public void removeObjects(List<DeleteObject> objects) {
            try {
                Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucket).objects(objects).build());
                for (Result<DeleteError> result : results) {
                    // 删除文件不存在时,不会报错
                    DeleteError error = result.get();
                    log.info("MinIO文件[{}]删除失败,{}", error.objectName(), error.message());
                }
                log.info("MinIO文件批量删除成功");
            } catch (Exception e) {
                throw new CustomException("MinIO文件批量删除失败," + e.getMessage());
            }
        }
    
        /**
         * 查询桶下对象
         *
         * @param recursive 是否递归查找,如果是false,就模拟文件夹结构查找。
         * @return {@link Item}
         */
        public List<Item> listObjects(boolean recursive) {
            List<Item> list = new ArrayList<>();
            try {
                Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucket).recursive(recursive).build());
                for (Result<Item> result : results) {
                    list.add(result.get());
                }
            } catch (Exception e) {
                throw new CustomException("MinIO文件查询失败," + e.getMessage());
            }
            return list;
        }
    
        /**
         * 条件查询
         *
         * @param prefix    前缀
         * @param recursive 是否递归
         * @return {@link Item}
         */
        public List<Item> listConditionsObjects(String prefix, boolean recursive) {
            List<Item> list = new ArrayList<>();
            try {
                Iterable<Result<Item>> listObjects = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucket)
                        .prefix(prefix).recursive(recursive).build());
                for (Result<Item> result : listObjects) {
                    list.add(result.get());
                }
            } catch (Exception e) {
                throw new CustomException("MinIO文件条件查询失败," + e.getMessage());
            }
            return list;
        }
    }
    
  5. 测试类

    import com.jiyang.common.utils.MinioUtils;
    import com.jiyang.common.utils.file.FileUtils;
    import io.minio.messages.DeleteObject;
    import io.minio.messages.Item;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.http.MediaType;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import javax.annotation.Resource;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * MinIO 测试类
     * 服务端部署方案参照文档 https://blog.csdn.net/jiahao1186/article/details/131024019
     *
     * @author wujie
     * @version 1.0
     */
    @RunWith(SpringRunner.class)
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    public class MinioTest {
    
        @Resource
        private MinioUtils minioUtils;
        // 对象名称
        static String objectName = "2022/08/18/111111.jpg";
    
        @Test
        public void presignedPutObject() {
            final String url = minioUtils.presignedPutObject(objectName, MediaType.IMAGE_JPEG_VALUE);
            System.out.println(url);
        }
    
        @Test
        public void presignedGetObject() {
            final String url = minioUtils.presignedGetObject("3b87e950352ac65c5eb643ddf9f2b21192138ae8.png", MediaType.IMAGE_PNG_VALUE);
            System.out.println(url);
        }
    
        @Test
        public void putObject() {
            final String s = minioUtils.uploadObject("测试1.xls", "D:\\software\\feiq\\Recv Files\\测试1.xls");
            System.out.println(s);
        }
    
        @Test
        public void getObject() throws IOException {
            final byte[] file = minioUtils.getObject("2022/08/18/111111.jpg");
            FileUtils.createFileByBytes("D:\\software\\feiq\\Recv Files\\00002.jpg", file);
        }
    
        @Test
        public void downloadObject() {
            minioUtils.downloadObject(objectName, "D:\\software\\feiq\\Recv Files\\000021.jpg");
        }
    
        @Test
        public void removeObject() {
            minioUtils.removeObject("2022/08/19/111111.jpg");
        }
    
        @Test
        public void removeObjects() {
            List<DeleteObject> objects = new ArrayList<>();
            objects.add(new DeleteObject("2022/08/19/111111.jpg"));
            objects.add(new DeleteObject("2022/08/19/2.svg"));
            minioUtils.removeObjects(objects);
        }
    
        @Test
        public void listObjects() {
            final List<Item> list = minioUtils.listObjects(true);
            for (final Item item : list) {
                System.out.println(item.objectName() + "\t" + item.size());
            }
        }
    
        @Test
        public void listConditionsObjects() {
            final List<Item> list = minioUtils.listConditionsObjects("", false);
            for (final Item item : list) {
                System.out.println(item.objectName() + "\t" + item.size());
                //2022/08/18/111111.jpg	864090
                //2022/08/19/049$ZY·DJ$43166$0003.jpg	844713
            }
        }
    }
    
0

评论