springboot使用minio(8.5.11)

1.配置minio MinioAutoConfiguration 类

java 复制代码
@AllArgsConstructor
@EnableConfigurationProperties({MinioProperties.class})
public class MinioAutoConfiguration {
    private final MinioProperties properties;

    @Bean
    @ConditionalOnMissingBean(MinioTemplate.class)
    @ConditionalOnProperty(name = "amc.minio.url")
    MinioTemplate minioTemplate() {
        return new MinioTemplate(
                properties.getUrl(),
                properties.getAccessKey(),
                properties.getSecretKey()
        );
    }
}

2.属性类

java 复制代码
@Data
@ConfigurationProperties(prefix = "amc.minio")
public class MinioProperties {
    /**
     * minio 服务地址 http://ip:port
     */
    private String url;

    /**
     * 用户名
     */
    private String accessKey;

    /**
     * 密码
     */
    private String secretKey;
}

3.创建minioTemplate工具类

java 复制代码
package com.amc.minio.entity;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;

/**
 * minio 交互类
 * @author Administrator
 */
@RequiredArgsConstructor
@Slf4j
public class MinioTemplate implements InitializingBean {
    private final String endpoint;
    private final String accessKey;
    private final String secretKey;
    private MinioClient client;

    /**
     * 创建bucket
     *
     * @param bucketName bucket名称
     */
    @SneakyThrows
    public void createBucket(String bucketName) {
        if (!client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
            client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     * 合并分片文件成对象文件
     *
     * @param chunkBucKetName   分片文件所在存储桶名称
     * @param composeBucketName 合并后的对象文件存储的存储桶名称
     * @param chunkNames        分片文件名称集合
     * @param objectName        合并后的对象文件名称
     * @return true/false
     */
    @SneakyThrows
    public boolean composeObject(String chunkBucKetName, String composeBucketName, List<String> chunkNames, String objectName) {
        if (null == chunkBucKetName) {
            chunkBucKetName = "chunk";
        }
        List<ComposeSource> sourceObjectList = new ArrayList<>(chunkNames.size());
        for (String chunk : chunkNames) {
            sourceObjectList.add(
                    ComposeSource.builder()
                            .bucket(chunkBucKetName)
                            .object(chunk)
                            .build()
            );
        }
        client.composeObject(
                ComposeObjectArgs.builder()
                        .bucket(composeBucketName)
                        .object(objectName)
                        .sources(sourceObjectList)
                        .build()
        );
        return true;
    }

    /**
     * 根据md5获取所有分片文件名称(minio的文件名称 = 文件path)
     * @param bucketName 桶(文件夹)名称
     * @param prefix 前缀
     * @return List<String>
     */
    @SneakyThrows
    public List<String> listObjectNames(String bucketName, String prefix) {
        List<String> chunkPaths = new ArrayList<>();

        ListObjectsArgs listObjectsArgs;
        if (StrUtil.isBlank(prefix)) {
            listObjectsArgs = ListObjectsArgs.builder()
                    .bucket(bucketName)
                    .recursive(true)
                    .build();
        } else {
            listObjectsArgs = ListObjectsArgs.builder()
                    .bucket(bucketName)
                    .prefix(prefix)
                    .recursive(true)
                    .build();
        }
        Iterable<Result<Item>> chunks = client.listObjects(listObjectsArgs);
        Iterator<Result<Item>> iterator = chunks.iterator();
        while(iterator.hasNext()) {
            Result<Item> item = iterator.next();
            chunkPaths.add(URLUtil.decode(item.get().objectName()));
        }
        return chunkPaths;
    }

    /**
     * 通过文件名字判断文件是否存在如果存在返回false否则返回true
     * @param bucketName 桶名称
     * @param fileName 文件名称
     * @return true|false
     */
    @SneakyThrows
    public Boolean fileExists(String bucketName, String fileName) {
        boolean exist = true;
        try {
            if(client.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build()) == null){
                exist = false;
            }
        } catch (Exception e) {
            exist = false;
        }
        return exist;
    }

    /**
     * 获取全部bucket
     * <p>
     * https://docs.minio.io/cn/java-client-api-reference.html#listBuckets
     */
    @SneakyThrows
    public List<Bucket> getAllBuckets() {
        return client.listBuckets();
    }

    /**
     * @param bucketName bucket名称
     */
    @SneakyThrows
    public Optional<Bucket> getBucket(String bucketName) {
        return client.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
    }

    /**
     * @param bucketName bucket名称
     */
    @SneakyThrows
    public Boolean bucketExists(String bucketName) {
        return client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }


    /**
     * @param bucketName bucket名称
     */
    @SneakyThrows
    public void removeBucket(String bucketName) {
        client.removeBucket(RemoveBucketArgs.builder()
                .bucket(bucketName)
                .build());
    }

    /**
     * 根据文件前置查询文件
     *
     * @param bucketName bucket名称
     * @param prefix     前缀
     * @param recursive  是否递归查询
     * @return MinioItem 列表
     */
    @SneakyThrows
    public List<MinioItem> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) {
        List<MinioItem> objectList = new ArrayList<>();
        Iterable<Result<Item>> objectsIterator = client.listObjects(ListObjectsArgs.builder()
                .bucket(bucketName)
                .prefix(prefix)
                .recursive(recursive)
                .build());

        for (Result<Item> itemResult : objectsIterator) {
            if(itemResult.get() != null) {
                objectList.add(new MinioItem(itemResult.get()));
            }
        }
        return objectList;
    }

    /**
     * 获取文件外链
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param expires    过期时间 <=7
     * @return url
     */
    @SneakyThrows
    public String getObjectUrl(String bucketName, String objectName, Integer expires) {
        return client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                .method(Method.GET)
                .bucket(bucketName)
                .object(objectName)
                .expiry(expires).build());
    }

    /**
     * 创建上传文件对象的外链
     *
     * @param bucketName 存储桶名称
     * @param objectName 欲上传文件对象的名称
     * @param expiry     过期时间(分钟) 最大为7天 超过7天则默认最大值
     * @return uploadUrl
     */
    @SneakyThrows
    public String createUploadUrl(String bucketName, String objectName, Integer expiry) {
        return client.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .method(Method.PUT)
                        .bucket(bucketName)
                        .object(objectName)
                        .expiry(expiry)
                        .build()
        );
    }

    /**
     * 获取文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return 二进制流
     */
    @SneakyThrows
    public InputStream getObject(String bucketName, String objectName) {
        return client.getObject(GetObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName).build());
    }

    /**
     * 从指定桶中获取对象的前缀输入流
     *
     * @param bucketName 桶名
     * @param objectName 对象名
     * @return 读取对象前1024字节的输入流,如果发生异常则返回null
     */
    public InputStream getPerfixInputStream(String bucketName, String objectName){
        // 读取文件的前1024字节
        // 你可以根据需要调整这个值
        long size = 1024;
        try {
            return   client.getObject(GetObjectArgs.builder()
                      .bucket(bucketName)
                      // 文件的起始位置
                      .offset(0L)
                      // 需要读取的字节数
                      .length(size)
                      .object(objectName).build());
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }
        return null;
    }

    /**
     * 下载到指定位置
     *
     * @param bucketName bucket名称
     * @param objectName 对象名称
     * @param objectName 文件名称
     * @return 二进制流
     */
    @SneakyThrows
    public void downloadObject(String bucketName, String objectName, String fileName) {
        client.downloadObject(DownloadObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                 //必须指定文件名
                .filename(fileName)
                .build());

    }

    /**
     * 复制文件
     *
     * @param srcBucketName Source bucket name
     * @param srcObjectName Source object name
     * @param bucketName    目标 bucket名称
     * @param objectName    目标 文件名称
     * @return 二进制流
     */
    @SneakyThrows
    public void copyObject(String srcBucketName, String srcObjectName, String bucketName, String objectName) {
        client.copyObject(CopyObjectArgs.builder()
                .source(CopySource.builder()
                        .bucket(srcBucketName)
                        .object(srcObjectName)
                        .build())
                .bucket(bucketName)
                .object(objectName)
                .build());
    }

    /**
     * 上传文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param stream     文件流
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
     */
    public void putObject(String bucketName, String objectName, InputStream stream) throws Exception {
        putObject(bucketName, objectName, stream, (long) stream.available(), "application/octet-stream");
    }

    /**
     * 上传文件
     *
     * @param bucketName  bucket名称
     * @param objectName  文件名称
     * @param stream      文件流
     * @param size        大小
     * @param contextType 类型
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
     */
    public void putObject(String bucketName, String objectName, InputStream stream, long size, String contextType) throws Exception {
        client.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName).stream(stream, size, -1)
                        .contentType(contextType)
                        .build());

    }

    /**
     * 获取文件信息
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#statObject
     */
    /*public ObjectStat getObjectInfo(String bucketName, String objectName) throws Exception {
        return client.statObject(
                StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }*/

    /**
     * 删除文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     */
    @SneakyThrows
    public void removeObject(String bucketName, String objectName) {
        client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }

    /**
     * 删除文件
     *
     * @param bucketName bucket名称
     * @param fileNames  文件名称列表
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#removeObject
     */
    @SneakyThrows
    public void removeObjects(String bucketName, List<String> fileNames) {

        fileNames.forEach(objectName -> {
            try {
                client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
            } catch (Exception e) {
                log.error(e.getMessage(),e);
            }
        });
    }


    /**
     * 删除文件
     *
     * @param bucketName bucket名称
     * @param fileNamePre  标识符
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#removeObject
     */
    @SneakyThrows
    public void removeObjects(String bucketName, String fileNamePre) {
        final List<String> listObjectNames = this.listObjectNames(bucketName, fileNamePre);
        this.removeObjects(bucketName,listObjectNames);
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        Assert.hasText(endpoint, "Minio url 为空");
        Assert.hasText(accessKey, "Minio accessKey为空");
        Assert.hasText(secretKey, "Minio secretKey为空");
        this.client = MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();

    }
}

4.初始化桶类

java 复制代码
@Slf4j
public class MinioBucketInit implements Runnable{

    /**
     算法文件存放的minio桶
     */
    public  String[] buckets;

    private MinioTemplate minioTemplate;

    public MinioBucketInit(MinioTemplate minioTemplate,String[] buckets) {
        this.minioTemplate = minioTemplate;
        this.buckets = buckets;
    }

    @Override
    public void run() {
        if(buckets==null) {
            return;
        }
        for (int i = 0; i <buckets.length ; i++) {
            //判断桶是否存在
            Boolean bucketNameExit = minioTemplate.bucketExists(buckets[i]);
            if(!bucketNameExit){
                minioTemplate.createBucket(buckets[i]);
            }
        }

    }
}

5.使用

java 复制代码
log.debug("初始化minio的桶");
            //判断有没有桶
threadPoolTaskExecutor.execute(new MinioBucketInit(minioTemplate,new String[]{bucketName}));
java 复制代码
  //获取源文件
InputStream inputStream = minioTemplate.getObject(attachment.getBucketName(), attachment.getFilePath());
  //判断文件是否存在
 Boolean fileExists = minioTemplate.fileExists(attachment.getBucketName(), attachment.getFilePath());
//上传文件到minio
minioTemplate.putObject(MinioBucketInit.ALGORITH_MBUCKET, path, inputStream);

6.注意

1.上传时如果流是空的,不上传不成功的

相关推荐
FF在路上27 分钟前
Knife4j调试实体类传参扁平化模式修改:default-flat-param-object: true
java·开发语言
真的很上进34 分钟前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
众拾达人1 小时前
Android自动化测试实战 Java篇 主流工具 框架 脚本
android·java·开发语言
皓木.1 小时前
Mybatis-Plus
java·开发语言
不良人天码星1 小时前
lombok插件不生效
java·开发语言·intellij-idea
守护者1701 小时前
JAVA学习-练习试用Java实现“使用Arrays.toString方法将数组转换为字符串并打印出来”
java·学习
源码哥_博纳软云2 小时前
JAVA同城服务场馆门店预约系统支持H5小程序APP源码
java·开发语言·微信小程序·小程序·微信公众平台
禾高网络2 小时前
租赁小程序成品|租赁系统搭建核心功能
java·人工智能·小程序
学会沉淀。2 小时前
Docker学习
java·开发语言·学习
如若1232 小时前
对文件内的文件名生成目录,方便查阅
java·前端·python