SpringBoot整合minio(实现minio-starter)

SpringBoot 整合minio(实现minio-starter)

1)依赖导入

<dependencies>

        <!-- 工具类相关 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
        <!-- Spring 核心 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-undertow</artifactId>
        </dependency>

        <!-- 三方云服务相关 -->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.5.7</version>
        </dependency>

    </dependencies>

2)配置编写

MinioAutoConfiguration

/**
 * minio自动配置类
 *
 * @author baiyan
 */
@Configuration
@EnableConfigurationProperties(MinioConfig.class)
public class MinioAutoConfiguration {

    @Bean
    public MinioClient minioClient(MinioConfig minioConfig) {
        return MinioClient.builder().endpoint(minioConfig.getEndpoint(), minioConfig.getPort(), minioConfig.getSecure())
            .credentials(minioConfig.getAccessKey(), minioConfig.getSecretKey()).build();
    }

    @Bean
    public MinioUtil minioUtil(MinioClient minioClient, MinioConfig minioConfig) {
        return new MinioUtil(minioClient, minioConfig);
    }

}
MinioConfig

@Data
@ConfigurationProperties(prefix = "spring.minio")
public class MinioConfig {
    /**
     * ip:minio地址,分布式节点情况下推荐配置一个nginx路由,转接给nginx的负载均衡
     */
    private String endpoint;

    /**
     * 端口:minio地址,分布式节点情况推荐配置一个nginx路由,转接给nginx的负载均衡
     */
    private int port;

    /**
     * 账号
     */
    private String accessKey;

    /**
     * 秘钥
     */
    private String secretKey;

    /**
     * 如果是true,则用的是https而不是http,默认值是false
     */
    private Boolean secure = false;

    /**
     * 桶名称,默认为baiyan
     */
    private String bucketName = "baiyan";

    /**
     * 是否开启nginx路由,与nginxLoadUrl对应
     */
    private Boolean nginxLoadUrlEnable = false;

    /**
     * 预览的url在nginx中的前缀,minio中生成的文件预览或者下载的url是直接展示成ip:端口形式的,这个是不安全的,需要在nginx中做一层路由。保证安全性,默认不开启。
     */
    private String nginxLoadUrl = "api/9c16ff1ecec";
}

3)工具类实现


/**
 * minio工具类
 *
 * @author zxl
 */
@Slf4j
@RequiredArgsConstructor
public class MinioUtil {

    /**
     * 默认url过期时间
     */
    public static final int DEFAULT_EXPIRY_TIME = 7 * 24 * 3600;
    /**
     * 默认最大文件上传为500M
     */
    public static final int MAX_UPLOAD_FILE_SIZE = 1024 * 1024 * 500;

    /**
     * @description Java Attribute variables
     */
    private final MinioClient minioClient;

    /**
     * @description Java Attribute variables
     */
    private final MinioConfig minioConfig;

    /**
     * @return string
     * @description Java Attribute variables 获取minio绝对路径
     * @param objectName
     */
    public String getAbsolutePath(String objectName) {
        return minioConfig.getEndpoint() + (minioConfig.getNginxLoadUrlEnable() ? minioConfig.getNginxLoadUrl() : "")
            + ":" + minioConfig.getPort() + "/" + minioConfig.getBucketName() + "/" + objectName;
    }

    /**
     * 检查存储桶是否存在
     *
     * @param bucketName 存储桶名称
     * @return boolean
     */
    @SneakyThrows
    public boolean bucketExists(String bucketName) {
        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }

    /**
     * 创建存储桶
     *
     * @param bucketName 存储桶名称
     */
    @SneakyThrows
    public void makeBucket(String bucketName) {
        if (!bucketExists(bucketName)) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     * 列出所有存储桶
     *
     * @return list of buckets
     */
    @SneakyThrows
    public List<Bucket> listBuckets() {
        return minioClient.listBuckets();
    }

    /**
     * 列出所有存储桶名称
     *
     * @return list
     */
    @SneakyThrows
    public List<String> listBucketNames() {
        List<Bucket> bucketList = listBuckets();
        return CollUtil.isNotEmpty(bucketList) ? bucketList.stream().map(Bucket::name).collect(Collectors.toList())
            : new ArrayList<>();
    }

    /**
     * 删除存储桶
     *
     * @param bucketName 存储桶名称
     * @return boolean
     */
    @SneakyThrows
    public boolean removeBucket(String bucketName) {
        boolean flag = bucketExists(bucketName);
        if (flag) {
            Iterable<Result<Item>> myObjects = listObjects(bucketName);
            for (Result<Item> result : myObjects) {
                Item item = result.get();
                // 有对象文件,则删除失败
                if (item.size() > 0) {
                    return false;
                }
            }
            // 删除存储桶,注意,只有存储桶为空时才能删除成功。
            minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
            flag = bucketExists(bucketName);
            if (!flag) {
                return true;
            }
        }
        return false;
    }

    /**
     * 列出存储桶中的所有对象名称
     *
     * @param bucketName 存储桶名称
     * @return list of
     */
    @SneakyThrows
    public List<String> listObjectNames(String bucketName) {
        List<String> listObjectNames = new ArrayList<>();
        boolean flag = bucketExists(bucketName);
        if (flag) {
            Iterable<Result<Item>> myObjects = listObjects(bucketName);
            for (Result<Item> result : myObjects) {
                Item item = result.get();
                listObjectNames.add(item.objectName());
            }
        }
        return listObjectNames;
    }

    /**
     * 列出存储桶中的所有对象
     *
     * @param bucketName 存储桶名称
     * @return item name
     */
    @SneakyThrows
    public Iterable<Result<Item>> listObjects(String bucketName) {
        boolean flag = bucketExists(bucketName);
        if (flag) {
            return minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).build());
        }
        return null;
    }

    /**
     * 获取文件md5
     *
     * @param stream
     * @return string
     */
    public String getFileMd5(InputStream stream) {
        return MD5.create().digestHex(stream);
    }

    /**
     * 获取文件md5
     *
     * @param multipartFile
     * @return str
     */
    @SneakyThrows
    public String getFileMd5(MultipartFile multipartFile) {
        return this.getFileMd5(multipartFile.getInputStream());
    }

    /**
     * 图片上传
     *
     * @param bucketName
     * @param multipartFile
     * @return string
     */
    @SneakyThrows
    public String putObject(String bucketName, MultipartFile multipartFile) {
        Assert.isTrue(multipartFile.getSize() <= MAX_UPLOAD_FILE_SIZE, "minio.upload.file.is.too.big");
        Assert.isTrue(bucketExists(bucketName), "minio.bucket.is.not.exist");
        // 获取当前日期
        LocalDateTime currentDate = LocalDateTime.now();
        // 创建一个日期格式化对象,指定格式为"yyyyMMdd"
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        // 将当前日期格式化为指定格式的字符串
        String currentTime = currentDate.format(formatter);
        String objectName = UUID.randomUUID().toString() + '_' + currentTime;
        log.info("minio的objectName为:{}", objectName);
        this.putObject(bucketName, multipartFile.getInputStream(), objectName, multipartFile.getContentType());
        return objectName;
    }

    /**
     * 通过InputStream上传对象,远端文件中心中存储的的文件名为上传流文件的md5值,保证远端存储的文件唯一性,业务端使用的使用可以根据md5进行文件的预览url获取或者流获取。
     *
     * @param bucketName 存储桶名称
     * @param path
     * @param multipartFile
     * @return string
     */
    @SneakyThrows
    public String putObjectWithPath(String bucketName, MultipartFile multipartFile, String path) {
        Assert.isTrue(multipartFile.getSize() <= MAX_UPLOAD_FILE_SIZE, "minio.upload.file.is.too.big");
        Assert.isTrue(bucketExists(bucketName), "minio.bucket.is.not.exist");
        // 获取当前日期
        LocalDateTime currentDate = LocalDateTime.now();
        // 创建一个日期格式化对象,指定格式为"yyyyMMdd"
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        // 将当前日期格式化为指定格式的字符串
        String currentTime = currentDate.format(formatter);
        String objectName = UUID.randomUUID().toString() + '_' + currentTime;
        log.info("minio的objectName为:{}", objectName);
        this.putObject(bucketName, multipartFile.getInputStream(), objectName, multipartFile.getContentType());
        return objectName;
    }

    /**
     * 通过InputStream上传对象,远端文件中心中存储的的文件名为上传流文件的md5值,保证远端存储的文件唯一性,业务端使用的使用可以根据md5进行文件的预览url获取或者流获取。
     *
     * @param bucketName 存储桶名称
     * @param stream 要上传的流
     * @param objectName minio中文件名:取MD5
     * @param contentType 文件类型
     * @return string
     */
    @SneakyThrows
    public String putObject(String bucketName, InputStream stream, String objectName, String contentType) {
        Assert.isTrue(bucketExists(bucketName), "minio.bucket.is.not.exist");
        Assert.isTrue(StrUtil.isNotBlank(objectName), "minio.objectName.is.not.exist");
        ObjectWriteResponse objectWriteResponse = minioClient.putObject(PutObjectArgs.builder().bucket(bucketName)
            .object(objectName).contentType(contentType).stream(stream, stream.available(), -1).build());
        return objectWriteResponse.object();
    }

    /**
     * description: 上传视频
     *
     * @param multipartFile
     * @param bucketName
     * @return string
     */
    public List<String> uploadVideo(String bucketName, MultipartFile[] multipartFile) {

        List<String> names = new ArrayList<>(multipartFile.length);
        for (MultipartFile file : multipartFile) {
            String fileName = file.getOriginalFilename();
            String[] split = fileName.split("\\.");
            if (split.length > 1) {
                fileName = split[0] + "_" + System.currentTimeMillis() + "." + split[1];
            } else {
                fileName = fileName + System.currentTimeMillis();
            }
            InputStream in = null;
            System.err.println("文件名是:" + fileName);
            try {
                in = file.getInputStream();
                File videoFile = File.createTempFile(split[0], "." + split[1]);
                FileUtils.copyInputStreamToFile(in, videoFile);
                System.err.println("路径" + videoFile.getAbsolutePath());
                File output = new File(videoFile.getAbsolutePath());
                InputStream inputStream = Files.newInputStream(output.toPath());
                minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(fileName)
                    .stream(inputStream, inputStream.available(), -1).contentType(file.getContentType()).build());
                inputStream.close();
                output.delete();
                videoFile.delete();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            names.add(fileName);
        }
        return names;
    }

    /**
     * 以流的形式获取一个文件对象
     *
     * @param bucketName 存储桶名称
     * @param objectName 存储桶里的对象名称
     * @return stream object
     */
    @SneakyThrows
    public InputStream getObject(String bucketName, String objectName) {
        boolean flag = bucketExists(bucketName);
        if (flag) {
            StatObjectResponse statObject = statObject(bucketName, objectName);
            if (statObject != null && statObject.size() > 0) {
                return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
            }
        }
        return null;
    }

    /**
     * 以流的形式获取一个文件对象(断点下载)
     *
     * @param bucketName 存储桶名称
     * @param objectName 存储桶里的对象名称
     * @param offset 起始字节的位置
     * @param length 要读取的长度 (可选,如果无值则代表读到文件结尾)
     * @return input
     */
    @SneakyThrows
    public InputStream getObject(String bucketName, String objectName, long offset, Long length) {
        boolean flag = bucketExists(bucketName);
        if (flag) {
            StatObjectResponse statObject = statObject(bucketName, objectName);
            if (statObject != null && statObject.size() > 0) {
                return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName)
                    .offset(offset).length(length).build());
            }
        }
        return null;
    }

    /**
     * 删除一个对象
     *
     * @param bucketName 存储桶名称
     * @param objectName 存储桶里的对象名称
     * @return boolean
     */
    @SneakyThrows
    public boolean removeObject(String bucketName, String objectName) {
        boolean flag = bucketExists(bucketName);
        if (flag) {
            minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
            return true;
        }
        return false;
    }

    /**
     * 删除指定桶的多个文件对象,返回删除错误的对象列表,全部删除成功,返回空列表
     *
     * @param bucketName 存储桶名称
     * @param objectNames 含有要删除的多个object名称的迭代器对象
     * @return list of objects
     */
    @SneakyThrows
    public List<String> removeObject(String bucketName, List<String> objectNames) {
        Assert.isTrue(CollUtil.isNotEmpty(objectNames), "minio.delete.object.name.can.not.empty");
        List<String> deleteErrorNames = new ArrayList<>();
        boolean flag = bucketExists(bucketName);
        if (flag) {
            List<DeleteObject> objects = objectNames.stream().map(DeleteObject::new).collect(Collectors.toList());
            Iterable<Result<DeleteError>> results =
                minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(objects).build());
            for (Result<DeleteError> result : results) {
                DeleteError error = result.get();
                deleteErrorNames.add(error.objectName());
            }
        }
        return deleteErrorNames;
    }

    /**
     * 生成一个给HTTP PUT请求用的presigned URL。 浏览器/移动端的客户端可以用这个URL进行上传,即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间,默认值是7天。
     *
     * @param bucketName 存储桶名称
     * @param objectName 存储桶里的对象名称
     * @param expires 失效时间(以秒为单位),默认是7天,不得大于七天
     * @return string
     */
    @SneakyThrows
    public String preSignedPutObject(String bucketName, String objectName, Integer expires) {
        boolean flag = bucketExists(bucketName);
        String url = "";
        if (flag) {
            url = minioClient
                .getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.PUT).bucket(bucketName)
                    .object(objectName).expiry(Objects.isNull(expires) ? DEFAULT_EXPIRY_TIME : expires).build());
        }
        return url;
    }

    /**
     * 获取对象的元数据
     *
     * @param bucketName 存储桶名称
     * @param objectName 存储桶里的对象名称
     * @return stat
     */
    @SneakyThrows
    public StatObjectResponse statObject(String bucketName, String objectName) {
        boolean flag = bucketExists(bucketName);
        if (flag) {
            return minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
        }
        return null;
    }

    /**
     * 获取URL地址
     *
     * @param bucketName 存储桶名称
     * @param objectName 存储桶里的对象名称
     * @return string
     */
    @SneakyThrows
    public String getObjectUrl(String bucketName, String objectName) {
        boolean flag = bucketExists(bucketName);
        String url = "";
        if (flag) {
            url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET)
                .bucket(bucketName).object(objectName).expiry(DEFAULT_EXPIRY_TIME).build());
        }
        return url;
    }

}
自动注入

注意:编写imports文件,实现springboot的主动注入功能

--- #minio 文件服务器配置
spring:
  minio:
    endpoint: ${MINIO_ENDPOINT:http://192.168.3.6}
    port: ${MINIO_PORT:6900}
    access-key: ${MINIO_ACCESS_KEY:admin}
    secret-key: ${MINIO_SECRET_KEY:password}
    bucket-name: ${MINIO_BUCKET_NAME:test}
posted @   zxlYY  阅读(65)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示