kotliin整合Minio

kotliin整合Minio

1.安装minio,请移步—> Docker安装Minio

2.在build.gradle文件中引入minio依赖

implementation 'io.minio:minio:8.3.1'

3.在yml文件中添加配置

minio:
  endpoint: http://192.168.209.136:9000 // minio 服务地址
  accessKey: minio	// 登录账号
  secretKey: minio123	// 登录密码

4.写配置类

package com.zo.config

import io.minio.MinioClient
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration


/**
 *
 * @author : WuZhiXing
 * @create : 2022/6/6 13:55 周一
 */
@Configuration
@ConfigurationProperties(prefix = "minio")
class MinIoConfig {

    /**
     * minio 服务地址 http://ip:port
     */
    var endpoint: String = ""

    /**
     * 访问密钥
     */
    var accessKey: String = ""

    /**
     * 密钥
     */
    var secretKey: String = ""

    /**
     * 初始化Minio客户端
     */
    @Bean
    fun initMinioClient(): MinioClient {
        return MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build()
    }
}

5.写工具类

package com.zo.util

import com.google.common.base.Preconditions
import com.zo.config.MinIoConfig
import io.minio.*
import io.minio.http.Method
import io.minio.messages.*
import io.minio.messages.Retention
import org.apache.commons.io.FileUtils
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
import org.springframework.web.multipart.MultipartFile
import java.io.ByteArrayInputStream
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
import java.time.ZonedDateTime
import java.util.concurrent.TimeUnit
import javax.activation.MimetypesFileTypeMap


/**
 *
 * @author : WuZhiXing
 * @create : 2022/6/6 13:55 周一
 */
@Component
class MinioTemplate{

    private val logger = LoggerFactory.getLogger(MinioTemplate::class.java)

    @Autowired
    lateinit var minIoConfig: MinIoConfig

    /**
     * 创建minio
     */
    fun minioClient(): MinioClient {
        return minIoConfig.initMinioClient()
    }

    /**
     * 判断桶是否存在
     */
    fun bucketExists(bucketName: String): Boolean {
        return minioClient().bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())
    }

    /**
     * 创建存储桶
     */
    fun createBucket(bucketName: String) {
        val bucketExists = bucketExists(bucketName)
        if (!bucketExists) {
            minioClient().makeBucket(MakeBucketArgs.builder().bucket(bucketName).build())
        }
    }

    /**
     * 创建一个给定区域的存储桶。
     * region: 描述的是服务器的物理位置,默认是us-east-1(美国东区1),S3的默认区域
     * 注:可以通过MINIO_REGION_NAME环境变量进行修改
     */
    fun createBucket(bucketName: String, regionName: String) {
        val bucketExists = bucketExists(bucketName)
        if (!bucketExists) {
            minioClient().makeBucket(MakeBucketArgs.builder().bucket(bucketName).region(regionName).build())
        }
    }

    /**
     * 创建一个启用给定区域和对象锁定功能的存储桶。
     * 对象锁定:可防止对象被删除。需要支持保留和合法保留。只能在创建存储桶时启用。
     */
    fun createBucket(bucketName: String, regionName: String, isLock: Boolean) {
        val bucketExists = bucketExists(bucketName)
        if (!bucketExists) {
            minioClient().makeBucket(MakeBucketArgs.builder().bucket(bucketName).region(regionName).objectLock(isLock).build())
        }
    }

    /**
     * 设置存储桶策略
     * config:JSON
     */
    fun setBucketPolicy(bucketName: String, policy: String) {
        minioClient().setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucketName).config(policy).build())
    }

    /**
     * 获取存储桶策略
     */
    fun getBucketPolicy(bucketName: String): String {
        return minioClient().getBucketPolicy(GetBucketPolicyArgs.builder().bucket(bucketName).build())
    }

    /**
     * TODO
     * 删除桶的桶策略配置
     */
    fun deleteBucketPolicy(bucketName: String) {
        minioClient().deleteBucketPolicy(DeleteBucketPolicyArgs.builder().bucket(bucketName).build())
    }

    /**
     * 设置桶的通知配置
     */
    fun setBucketNotification(bucketName: String, config: NotificationConfiguration) {
        return minioClient().setBucketNotification(SetBucketNotificationArgs.builder().bucket(bucketName).config(config).build())
    }

    /**
     * 获取桶的通知配置
     */
    fun getBucketNotification(bucketName: String): NotificationConfiguration {
        return minioClient().getBucketNotification(GetBucketNotificationArgs.builder().bucket(bucketName).build())
    }

    /**
     * 删除桶的通知配置
     */
    fun deleteBucketNotification(bucketName: String) {
        minioClient().deleteBucketNotification(DeleteBucketNotificationArgs.builder().bucket(bucketName).build())
    }

    /**
     * 列出所有存储桶的桶信息
     */
    fun listBuckets(): List<Bucket> {
        return minioClient().listBuckets()
    }

    /**
     * 列出所有存储桶的桶信息详情
     * listBuckets: 存储桶集合
     * return 创建时间是美国时间
     */
    fun listBucketsDetail(listBuckets: List<Bucket>): List<BucketDetail> {
        val bucketDetails = mutableListOf<BucketDetail>()
        for (bucket in listBuckets) {
            val bucketDetail = BucketDetail()
            bucketDetail.bucketName = bucket.name()
            bucketDetail.creationDate = bucket.creationDate()
            bucketDetails.add(bucketDetail)
        }
        return bucketDetails
    }

    /**
     * 删除桶: 必须是空桶,否则报错
     */
    fun removeBucket(bucketName: String) {
        val bucketExists = bucketExists(bucketName)
        // TODO 判断桶是否为空
        if (bucketExists) {
            minioClient().removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build())
        }
    }

    /**
     * 桶的对象信息列表:列出桶的对象信息
     */
    fun listObjects(bucketName: String): Iterable<Result<Item>> {
        return minioClient().listObjects(ListObjectsArgs.builder().bucket(bucketName).build())
    }

    /**
     * 桶的对象信息列表:递归查询存储桶下文件信息
     */
    fun listObjects(bucketName: String, recursive: Boolean = true): Iterable<Result<Item>> {
        return minioClient().listObjects(ListObjectsArgs.builder().bucket(bucketName).recursive(recursive).build())
    }

    /**
     * 桶的对象信息列表:条件查询,指定前缀、后缀、最大数量
     * 最多列出 maxKeys 个名称以 prefix 开头并在 startAfter 之后的对象信息。
     * startAfter:在..之后
     * prefix: 前缀
     * maxKeys: 最大数量
     */
    fun listObjects(bucketName: String, startAfter: String, prefix: String, maxKeys: Int): Iterable<Result<Item>> {
        return minioClient().listObjects(ListObjectsArgs.builder().bucket(bucketName).startAfter(startAfter).prefix(prefix).maxKeys(maxKeys).build())
    }

    /**
     * 列出最多 maxKeys 个对象信息,其版本名称以 prefix 开头并在 startAfter 之后。
     */
    fun listObjects(bucketName: String, startAfter: String, prefix: String, maxKeys: Int, includeVersions: Boolean = true): Iterable<Result<Item>> {
        return minioClient().listObjects(ListObjectsArgs.builder().bucket(bucketName).startAfter(startAfter).prefix(prefix).maxKeys(maxKeys).includeVersions(includeVersions).build())
    }

    /**
     * TODO
     * 设置桶的加密配置
     */
    fun setBucketEncryption(bucketName: String, config: SseConfiguration) {
        minioClient().setBucketEncryption(SetBucketEncryptionArgs.builder().bucket(bucketName).config(config).build())
    }

    /**
     * TODO
     * 获取桶的加密配置
     */
    fun getBucketEncryption(bucketName: String): SseConfiguration {
        return minioClient().getBucketEncryption(GetBucketEncryptionArgs.builder().bucket(bucketName).build())
    }

    /**
     * 删除桶的加密配置
     */
    fun deleteBucketEncryption(bucketName: String) {
        minioClient().deleteBucketEncryption(DeleteBucketEncryptionArgs.builder().bucket(bucketName).build())
    }

    /**
     * TODO
     * 设置桶的复制配置
     */
    fun setBucketReplication(bucketName: String, config: ReplicationConfiguration) {
        minioClient().setBucketReplication(SetBucketReplicationArgs.builder().bucket(bucketName).config(config).build())
    }

    /**
     * TODO
     * 获取桶的复制配置
     */
    fun getBucketReplication(bucketName: String): ReplicationConfiguration {
        return minioClient().getBucketReplication(GetBucketReplicationArgs.builder().bucket(bucketName).build())
    }

    /**
     * 删除桶的复制配置
     */
    fun deleteBucketReplication(bucketName: String) {
        minioClient().deleteBucketReplication(DeleteBucketReplicationArgs.builder().bucket(bucketName).build())
    }

    /**
     * TODO
     * 为存储桶设置标签
     */
    fun setBucketTags(bucketName: String, tagMap: MutableMap<String, String>) {
        minioClient().setBucketTags(SetBucketTagsArgs.builder().bucket(bucketName).tags(tagMap).build())
    }

    /**
     * TODO
     * 获取桶的标签
     */
    fun getBucketTags(bucketName: String): Tags {
        return minioClient().getBucketTags(GetBucketTagsArgs.builder().bucket(bucketName).build())
    }

    /**
     * TODO
     * 删除桶的标签
     */
    fun deleteBucketTags(bucketName: String) {
        minioClient().deleteBucketTags(DeleteBucketTagsArgs.builder().bucket(bucketName).build())
    }

    /**
     * 设置存储桶的版本控制配置
     */
    fun setBucketVersioning(bucketName: String, isOpen: Boolean) {
        if (isOpen) {
            minioClient().setBucketVersioning(SetBucketVersioningArgs.builder().bucket(bucketName).config(VersioningConfiguration(VersioningConfiguration.Status.ENABLED, null)).build())
        } else {
            minioClient().setBucketVersioning(SetBucketVersioningArgs.builder().bucket(bucketName).config(VersioningConfiguration(VersioningConfiguration.Status.SUSPENDED, null)).build())
        }
    }

    /**
     * 获取存储桶的版本控制配置
     */
    fun getBucketVersioning(bucketName: String): VersioningConfiguration {
        return minioClient().getBucketVersioning(GetBucketVersioningArgs.builder().bucket(bucketName).build())
    }

    /**
     * TODO
     * 在存储桶中设置对象锁定配置:对象锁定设置后,删除对象后,会仍然存在磁盘中
     */
    fun setObjectLockConfiguration(
        bucketName: String,
        // 将保留模式设置为Compliance,且持续时间为100天
        config: ObjectLockConfiguration? = ObjectLockConfiguration(
            RetentionMode.COMPLIANCE,
            RetentionDurationDays(100)
        )
    ) {
        minioClient().setObjectLockConfiguration(SetObjectLockConfigurationArgs.builder().bucket(bucketName).config(config).build())
    }

    /**
     * 获取存储桶中的对象锁定配置
     */
    fun getObjectLockConfiguration(bucketName: String): ObjectLockConfiguration {
        return minioClient().getObjectLockConfiguration(GetObjectLockConfigurationArgs.builder().bucket(bucketName).build())
    }

    /**
     * 删除存储桶的对象锁定配置
     */
    fun deleteObjectLockConfiguration(bucketName: String){
        minioClient().deleteObjectLockConfiguration(DeleteObjectLockConfigurationArgs.builder().bucket(bucketName).build())
    }

    /**
     * 设置存储桶生命周期配置
     */
    fun setBucketLifecycle(bucketName: String, rules: MutableList<LifecycleRule>) {
        val lifecycleConfiguration = LifecycleConfiguration(rules)
        minioClient().setBucketLifecycle(SetBucketLifecycleArgs.builder().bucket(bucketName).config(lifecycleConfiguration).build())
    }

    /**
     * TODO
     * 获取存储桶生命周期配置
     */
    fun getBucketLifecycle(bucketName: String): LifecycleConfiguration{
        return minioClient().getBucketLifecycle(GetBucketLifecycleArgs.builder().bucket(bucketName).build())
    }

    /**
     * 删除存储桶的生命周期配置
     */
    fun deleteBucketLifecycle(bucketName: String){
        minioClient().deleteBucketLifecycle(DeleteBucketLifecycleArgs.builder().bucket(bucketName).build())
    }

    /**
     * 上传文件:上传multipartFile通用方法
     */
    fun putObject(bucketName: String, destPath: String, file: MultipartFile) {
        minioClient().putObject(
            PutObjectArgs.builder().bucket(bucketName).`object`(destPath).contentType(file.contentType).stream(
                file.inputStream,
                file.inputStream.available().toLong(), -1
            ).build()
        )
    }

    /**
     * 上传文件:将给定的流上传为存储桶中的对象 上传inputStream通用方法
     * 注:1.添加的Object大小不能超过 5GB
     *    2.默认情况下,如果已存在同名Object且对该Object有访问权限,则新添加的Object将覆盖原有的Object
     *    3.上传文件是也可以使用SSE-C加密,添加自定义元数据及消息头等操作
     */
    fun putObject(bucketName: String, destPath: String?, contentType: String?, stream: InputStream) {
        // 上传流
        minioClient().putObject(
            PutObjectArgs.builder()
                .bucket(bucketName)
                .`object`(destPath)
                .stream(stream, stream.available().toLong(), -1)
                .contentType(contentType)
                .build()
        )
        stream.close()
    }

    /**
     * 上传文件:上传bytes通用方法
     */
    fun putObject(bucketName: String, destPath: String?, contentType: String?, bytes: ByteArray) {
        // 字节转文件流
        val stream = ByteArrayInputStream(bytes)
        // 上传流
        minioClient().putObject(
            PutObjectArgs.builder()
                .bucket(bucketName)
                .`object`(destPath)
                .stream(stream, stream.available().toLong(), -1)
                .contentType(contentType)
                .build()
        )
        stream.close()
    }

    /**
     * 上传文件:上传file通用方法
     */
    fun putObject(bucketName: String, destPath: String, file: File, contentType: String?) {
        val stream = FileInputStream(file)
        minioClient().putObject(
            PutObjectArgs.builder().bucket(bucketName).`object`(destPath).contentType(contentType).stream(
                stream,
                stream.available().toLong(), -1
            ).build()
        )
    }

    /**
     * 上传文件:将文件中的内容作为存储桶中的对象上传
     * 注:不太常用,一般适合上传磁盘文件
     */
    fun uploadObject(bucketName: String, destPath: String, sourcePath: String, contentType: String) {
        val bucketExists = this.bucketExists(bucketName)
        if (!bucketExists) {
            this.createBucket(bucketName)
        }
        minioClient().uploadObject(
            UploadObjectArgs.builder()
                .bucket(bucketName)         // 桶名
                .`object`(destPath)         // 上传到minio后的文件路径
                .filename(sourcePath)       // 源文件路径
                .contentType(contentType)   //文件类型
                .build()
        )
    }

    /**
     * 获取对象:GetObject接口用于获取某个文件(Object)。
     * 此操作需要对此Object具有读权限。
     * 获取对象的数据。InputStream使用后返回必须关闭以释放网络资源。
     */
    fun getObject(bucketName: String, sourcePath: String, destPath: String) {
        // 获取对象的InputStream
        val stream =
            minioClient().getObject(GetObjectArgs.builder().bucket(bucketName).`object`(sourcePath).build())
        // 读流
        val sourceFile = File(destPath)
        FileUtils.copyInputStreamToFile(stream, sourceFile)
//        println(stream.bucket() + stream.headers() + stream.`object`() + stream.region())
        stream.close()
    }

    /**
     * 下载文件:将对象的数据下载到磁盘
     */
    fun downloadObject(bucketName: String, sourcePath: String, destPath: String) {
        minioClient().downloadObject(DownloadObjectArgs.builder()
            .bucket(bucketName)
            .`object`(sourcePath)
            .filename(destPath)
            .build())
    }

    /**
     * 获取一个指定了HTTP方法、到期时间和自定义请求参数的对象URL地址,也就是返回带签名的URL,这个地址可以提供给没有登录的第三方共享访问或者上传对象。
     * 注:返回带签名的URL有点小长,过期之后访问会报错
     */
    fun getPreSignedObjectUrl(bucketName: String, sourcePath: String): String {
        return minioClient().getPresignedObjectUrl(
            GetPresignedObjectUrlArgs.builder()
                .method(Method.GET)
                .bucket(bucketName)
                .`object`(sourcePath)   // 默认:秒
                .build()
        )
    }

    fun getPreSignedObjectUrl(bucketName: String, sourcePath: String, expiryTime: Int, timeUnit: TimeUnit?): String {
        return if (timeUnit == null) {
            minioClient().getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(bucketName)
                    .`object`(sourcePath)
                    .expiry(expiryTime)
                    .build()
            )
        } else {
            minioClient().getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(bucketName)
                    .`object`(sourcePath)
                    .expiry(expiryTime, timeUnit)
                    .build()
            )
        }
    }

    /**
     * 判断文件是否存在
     * @param objectName 文件名称,如需带文件夹请用/分割
     */
    fun checkFileExist(bucketName: String, objectName: String): Boolean {
        try {
            val bucketExists = bucketExists(bucketName)
            if (bucketExists) {
                minioClient().statObject(StatObjectArgs.builder().bucket(bucketName).`object`(objectName).build())
            }
        } catch (e: Exception) {
            logger.error("文件不存在: {}", e.message)
            return false
        }
        return true
    }

    /**
     * 复制对象:通过服务器端从另一个对象复制数据来创建一个对象
     * 将sourceBucketName下的sourcePath 复制到 destBucketName下的destPath
     * 将源存储桶中的源路径文件复制到目标桶中
     */
    fun copyObject(destBucketName: String, destPath: String, sourceBucketName: String, sourcePath: String) {
        minioClient().copyObject(
            CopyObjectArgs.builder()
                .bucket(destBucketName)
                .`object`(destPath)
                .source(CopySource.builder().bucket(sourceBucketName).`object`(sourcePath).build())
                .build()
        )
    }

    /**
     * 删除对象:移除一个对象
     */
    fun removeObject(bucketName: String, sourcePath: String) {
        minioClient().removeObject(RemoveObjectArgs.builder().bucket(bucketName).`object`(sourcePath).build())
    }

    /**
     * 删除对象:移除一个指定版本号对象
     */
    fun removeObject(bucketName: String, sourcePath: String, versionId: String) {
        minioClient().removeObject(RemoveObjectArgs.builder().bucket(bucketName).`object`(sourcePath).versionId(versionId).build())
    }

    /**
     * TODO 测试无法删除
     * 懒惰地删除多个对象
     * 它需要迭代返回的 Iterable 以执行删除
     * 文件不存在不会报错
     */
    fun removeObjects(bucketName: String, deleteObjects: MutableList<DeleteObject>): Iterable<Result<DeleteError>> {
        return minioClient().removeObjects(
            RemoveObjectsArgs.builder().bucket(bucketName).objects(deleteObjects).build()
        )
    }

    /**
     * 获取文件信息
     */
    fun statObject(bucketName: String, sourcePath: String): StatObjectResponse{
        return minioClient().statObject(StatObjectArgs.builder().bucket(bucketName).`object`(sourcePath).build())
    }

    fun composeSource(bucketName: String, sourcePath: String): ComposeSource {
        return ComposeSource.builder().bucket(bucketName).`object`(sourcePath).build()
    }

    /**
     * 组合对象:通过使用服务器端副本组合来自不同源对象的数据来创建对象,比如可以将文件分片上传,然后将他们合并为一个文件
     */
    fun composeObject(destBucketName: String, destPath: String, sources: MutableList<ComposeSource>): ObjectWriteResponse {
        return minioClient().composeObject(ComposeObjectArgs.builder().bucket(destBucketName).`object`(destPath).sources(sources).build())
    }

    /**
     * 获取对象的保留配置: 没有保留配置会报错
     */
    fun getObjectRetention(bucketName: String, sourcePath: String): Retention {
        val retention = minioClient().getObjectRetention(
            GetObjectRetentionArgs.builder()
                .bucket(bucketName)
                .`object`(sourcePath).build()
        )
        Preconditions.checkArgument(retention != null, "该对象未设置保留配置")
        return retention
    }

    /**
     * 添加对象的保留配置:存储桶需要设置为对象锁定模式,并且没有开启版本控制,否则会报错收蠕虫保护
     */
    fun setObjectRetention(bucketName: String, sourcePath: String, dateTime: ZonedDateTime) {
        minioClient().setObjectRetention(SetObjectRetentionArgs.builder().bucket(bucketName).`object`(sourcePath).config(Retention(RetentionMode.COMPLIANCE, dateTime)).bypassGovernanceMode(true).build())
    }

    /**
     * 禁用对对象的合法保留
     */
    fun disableObjectLegalHold(bucketName: String, sourcePath: String) {
        minioClient().disableObjectLegalHold(DisableObjectLegalHoldArgs.builder().bucket(bucketName).`object`(sourcePath).build())
    }

    /**
     * 启用对对象的合法保留
     */
    fun enableObjectLegalHold(bucketName: String, sourcePath: String) {
        minioClient().enableObjectLegalHold(EnableObjectLegalHoldArgs.builder().bucket(bucketName).`object`(sourcePath).build())
    }

    /**
     * 如果在对象上启用了合法保留,则返回 true
     */
    fun isObjectLegalHoldEnabled(bucketName: String, sourcePath: String): Boolean {
        return minioClient().isObjectLegalHoldEnabled(IsObjectLegalHoldEnabledArgs.builder().bucket(bucketName).`object`(sourcePath).build())
    }

    /**
     * 如果在对象上启用了合法保留,则返回 true
     */
    fun isObjectLegalHoldEnabled(bucketName: String, sourcePath: String, versionId: String): Boolean {
        return minioClient().isObjectLegalHoldEnabled(IsObjectLegalHoldEnabledArgs.builder().bucket(bucketName).`object`(sourcePath).versionId(versionId).build())
    }

     /**
     *获取对象的标签。
     */
    fun getObjectTags(bucketName: String, sourcePath: String): Tags {
        return minioClient().getObjectTags(
            GetObjectTagsArgs.builder().bucket(bucketName).`object`(sourcePath).build())
    }
}

data class BucketDetail(
    var bucketName: String? = null,
    var creationDate: ZonedDateTime? = null
)

// 通过文件名/文件路径获取contentType
fun String.getContentType() = MimetypesFileTypeMap().getContentType(File(this))


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值