首页 > 其他分享 >SpringBoot整合minio(实现minio-starter)

SpringBoot整合minio(实现minio-starter)

时间:2025-01-22 14:45:35浏览次数:1  
标签:SpringBoot return String objectName param bucketName public starter minio

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}

标签:SpringBoot,return,String,objectName,param,bucketName,public,starter,minio
From: https://www.cnblogs.com/zxlyy/p/18685863

相关文章

  • high performance object storage | MinIO vs. Ceph
    -[MinIO|Codeanddownloadstocreatehighperformanceobjectstorage](https://min.io/download)-[Ceph.io—Code](https://ceph.io/en/developers/code/)-[Indexof/tarballs/](https://download.ceph.com/tarballs/)-[GitHub-ceph/ceph:Cephisadistribut......
  • SpringBoot(Spring)中为什么不推荐使用@Autowired?
    在Spring框架中,依赖注入是一种常见的设计模式,用于实现对象之间的解耦。Spring提供了多种依赖注入的方式,其中@Autowired注解是最常用的一种。然而,在SpringBoot中,官方并不推荐使用@Autowired注解进行依赖注入,而是推荐使用构造函数注入。本文将详细分析为什么不推荐使用@Autowired......
  • 计算机毕业设计Springboot基于的露营活动装备租凭系统 基于Spring Boot的户外露营装备
    计算机毕业设计Springboot基于的露营活动装备租凭系统6fnmr8bp(配套有源码程序mysql数据库论文)本套源码可以先看具体功能演示视频领取,文末有联xi可分享随着户外露营活动的兴起,越来越多的人开始追求亲近自然的生活方式。然而,高昂的露营装备购置成本、使用后的存放问题以及......
  • 计算机毕业设计Springboot基于大数据的红色旅游景点可视化安全分析系统 基于Spring Bo
    计算机毕业设计Springboot基于大数据的红色旅游景点可视化安全分析系统995q07gh(配套有源码程序mysql数据库论文)本套源码可以先看具体功能演示视频领取,文末有联xi可分享随着信息技术的飞速发展和大数据时代的到来,红色旅游作为中国文化旅游的重要组成部分,承载着丰富的历史......
  • 计算机毕业设计Springboot基于Java的医院床位管理系统 基于Spring Boot的Java医院床位
    计算机毕业设计Springboot基于Java的医院床位管理系统18b553a9(配套有源码程序mysql数据库论文)本套源码可以先看具体功能演示视频领取,文末有联xi可分享随着医疗行业的不断发展,医院床位管理系统的开发成为了提升医疗服务效率的关键环节。传统的人工管理方式不仅效率低下,还......
  • 基于Springboot的大学生二手电子产品交易平台的设计与实现
    ......
  • 2025毕设springboot 基于的网上招聘系统的设计与实现论文+源码
    系统程序文件列表开题报告内容研究背景随着互联网技术的迅猛发展和普及,网络已经成为人们获取信息、交流互动的重要平台。在人力资源领域,传统的招聘方式逐渐暴露出效率低下、信息不对称等问题。而网上招聘系统作为一种新兴的招聘模式,凭借其便捷性、高效性和广泛性,正逐步取代......
  • 2025毕设springboot 基于的网上订餐系统的设计与实现论文+源码
    系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展,人们的生活方式正发生着深刻的变化,特别是在餐饮消费领域,网上订餐已成为一种普遍现象。传统的餐饮消费模式往往需要消费者亲自前往餐厅点餐,不仅耗时费力,还受到地理位置和营业时间的限制。而基于互联网的网上订......
  • 2025毕设springboot 基于的土地档案管理系统论文+源码
    系统程序文件列表开题报告内容研究背景土地作为国家重要的自然资源,其管理和利用直接关系到国家的经济发展和社会稳定。随着城市化进程的加速,土地资源的开发和利用日益频繁,土地档案管理工作显得尤为重要。传统的土地档案管理方式多以纸质档案为主,不仅占用大量空间,而且在查询......
  • springboot毕设 基于SpringBoot远程教学网页前端的设计与实现 程序+论文
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展和普及,教育领域正经历着深刻的变革。传统面对面的教学模式虽然具有其独特的优势,但在时空限制、资源分配以及个性化学习需求......