MINIO


前言

简介

  • 官网地址:https://docs.min.io/cn/
  • MinIO 是在 Apache License v2.0 下发布的对象存储服务器。 它与 Amazon S3 云存储服务兼容。 它最适合存储非结构化数据,如照片,视频,日志文件,备份和容器/ VM 映像。 对象的大小可以从几 KB 到最大 5TB。
  • MinIO 服务器足够轻,可以与应用程序堆栈捆绑在一起,类似于 NodeJS,Redis 和 MySQL。
  • 一种高性能的分布式对象存储服务器,用于大型数据基础设施。它是机器学习和其他大数
    据工作负载下 Hadoop HDFS 的理想 s3 兼容替代品

优点/选择的原因

  • Minio 有良好的存储机制
  • Minio 有很好纠删码的算法与擦除编码算法
  • 拥有RS code 编码数据恢复原理
  • 公司做强做大时,数据的拥有重要性,对数据治理与大数据分析做准备。
  • 搭建自己的一套文件系统服务,对文件数据进行安全保护。
  • 拥有自己的平台,不限于其他方限制。

一、安装/配置及启动

安装及启动
启动后会打印出 AccessKey 和 SecretKey 等信息

默认配置

  • 默认 AccessKey 和 SecretKey
    • AccessKey:minioadmin
    • SecretKey:minioadmin
  • 自定义 AccessKey 和 SecretKey
    • export MINIO_ACCESS_KEY=minio
    • export MINIO_SECRET_KEY=miniostorage
  • 默认端口
    • 9000
  • 自定义端口
    • --address 0.0.0.0:9001
  • 自定义文件夹地址
    • export MINIO_VOLUMES="/home/minio/data"

访问

  • 本机访问:默认端口(http://127.0.0.1:9000

二、使用

  1. 访问http://127.0.0.1:9000进行登录
  2. 创建Bucket :选择Administrator-Buckets菜单,单击右侧Create Buckets按钮进入Bucket创建页面进行创建
    在这里插入图片描述
    在这里插入图片描述
  3. 选择:User-Object Browser菜单,并单击右侧 Bucket 进入管理文件页面

    4.上传:选择右侧Upload上传按钮即可上传
    在这里插入图片描述

三、MINIO 基础概念

  • Object:存储到 Minio 的基本对象,如文件、字节流,Anything…

  • Bucket:用来存储 Object 的逻辑空间。每个 Bucket 之间的数据是相互隔离的。对于客户端而言,就相当于一个存放文件的顶层文件夹。

  • Drive:即存储数据的磁盘,在 MinIO 启动时,以参数的方式传入。Minio 中所有的对象数据都会存储在 Drive 里。

  • Set:即一组 Drive 的集合

    • 每个 Set 中的 Drive 分布在不同位置。
    • 一个对象存储在一个Set上
    • 一个集群划分为多个Set
    • 一个Set包含的Drive数量是固定的,默认由系统根据集群规模自动计算得出
    • 一个SET中的Drive尽可能分布在不同的节点上

四、Java中上传文件MinIO服务器

1、引入 maven 依赖及配置

引入maven

		<!-- minio 相关依赖 -->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.4.3</version>
        </dependency>
        <!-- alibaba的fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.23</version>
        </dependency>
        <!-- thymeleaf模板引擎 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

application.yml配置

server:
  port: 2546
minio:
  endpoint: http://127.0.0.1:9000 #MinIO服务所在地址
  port: 9000
  bucketName: filestorebucket #存储桶名称
  accessKey: admin #访问的key
  secretKey: adminadmin  #访问的秘钥
  secure: false

将配置文件中 minio 的配置信息通过注解的方式注入到 MinioProp ,方便后续使用

/**
 * minio 属性值
 */
@Data
@Component
@ConfigurationProperties(prefix = "minio")
public class MinioProp {
    /**
     * 连接url
     */
    private String endpoint;
    /**
     * 端口
     */
    private String port;
    /**
     * 存储桶名称
     */
    private String bucketName;
    /**
     * 用户名
     */
    private String accesskey;
    /**
     * 密码
     */
    private String secretKey;

    
    private String secure;
}

核心配置类

/**
 * minio 核心配置类
 */
@Configuration
@EnableConfigurationProperties(MinioProp.class)
public class MinioConfig {

    @Autowired
    private MinioProp minioProp;

    /**
     * 获取 MinioClient
     *
     */
    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder()
                .endpoint(minioProp.getEndpoint())
                .credentials(minioProp.getAccesskey(),minioProp.getSecretKey())
                .build();
    }
}

2、示例代码

工具类

/**
 * Minio工具类
 *
 * @author wh
 * @version 1.0.0
 */
@Slf4j
@Component
public class MinioUtils {


    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

    @Value("${minio.bucketName}")
    private String BUCKET_NAME;
    @Value("${minio.endpoint}")
    private String ENDPOINT;
    @Resource
    public MinioClient minioClient;


    /**
     * 判断桶是否存在
     *
     * @param bucketName bucket名称
     * @return true存在,false不存在
     */
    public Boolean bucketExists(String bucketName) {
        try {
            return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            throw new RuntimeException("检查桶是否存在失败!", e);
        }
    }

    /**
     * 创建bucket
     *
     * @param bucketName bucket名称
     */
    public void createBucket(String bucketName) {
        if (this.bucketExists(bucketName)) {
            log.info("存储桶已经存在!");
        } else {
            try {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            } catch (Exception e) {
                throw new RuntimeException("创建桶失败!", e);
            }
        }
    }

    /**
     * 创建只读bucket
     *
     * @param bucketName bucket名称
     */
    public void createReadOnlyBucket(String bucketName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        if (this.bucketExists(bucketName)) {
            log.info("存储桶已经存在!");
        } else {
            //创建存储桶并设置只读权限
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            BucketPolicyConfig bucketPolicyConfig = createBucketPolicyConfig(bucketName);
            SetBucketPolicyArgs setBucketPolicyArgs = SetBucketPolicyArgs.builder()
                    .bucket(bucketName)
                    .config(JSONObject.toJSONString(bucketPolicyConfig))
                    .build();
            minioClient.setBucketPolicy(setBucketPolicyArgs);
        }
    }

    private BucketPolicyConfig createBucketPolicyConfig(String bucketName) {
        BucketPolicyConfig.Statement statement = BucketPolicyConfig.Statement.builder()
                .Effect("Allow")
                .Principal("*")
                .Action("s3:GetObject")
                .Resource("arn:aws:s3:::" + bucketName + "/*.**").build();
        return BucketPolicyConfig.builder()
                .Version("2012-10-17")
                .Statement(Collections.singletonList(statement))
                .build();
    }

    /**
     * 上传MultipartFile文件到全局默认文件桶中
     *
     * @param file 文件
     * @return 文件对应的URL
     */
    public String putObject(MultipartFile file) {

        // 给文件名添加时间戳防止重复
        String fileName = FileUtil.renFileName(Objects.requireNonNull(file.getOriginalFilename()));

        String objectName = sdf.format(new Date()) + "/" + fileName;
        // 开始上传
        this.putMultipartFile(BUCKET_NAME, objectName, file);
        log.info("文件上传成功!");
        return objectName;
    }

    /**
     * 上传文件
     *
     * @param fileName    文件名
     * @param stream      文件流
     * @param contentType 文件类型, 例如 image/jpeg: jpg图片格式, 点击查看: <a href="https://www.runoob.com/http/http-content-type.html">图片格式</a>
     * @return 文件url
     */
    public String putObject(@NotNull String fileName, @NotNull InputStream stream, @NotNull String contentType) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        this.createReadOnlyBucket(BUCKET_NAME);
        // 给文件名添加时间戳防止重复
        String objectName = sdf.format(new Date()) + "/" + FileUtil.renFileName(fileName);
        // 开始上传
        this.putInputStream(BUCKET_NAME, objectName, stream, contentType);
        return ENDPOINT + "/" + BUCKET_NAME + "/" + objectName;
    }

    /**
     * 上传bytes文件
     *
     * @param fileName    文件名
     * @param bytes       字节
     * @param contentType 文件类型, 例如 image/jpeg: jpg图片格式, 点击查看: <a href="https://www.runoob.com/http/http-content-type.html">图片格式</a>
     * @return 文件url
     */
    public String putObject(String fileName, byte[] bytes, String contentType) {
        // 给文件名添加时间戳防止重复
        String objectName = sdf.format(new Date()) + "/" + FileUtil.renFileName(fileName);
        // 开始上传
        this.putBytes(BUCKET_NAME, objectName, bytes, contentType);
        return ENDPOINT + "/" + BUCKET_NAME + "/" + objectName;
    }

    /**
     * 上传MultipartFile文件到指定的文件桶下
     *
     * @param bucketName 桶名称
     * @param file       文件
     * @return 文件对应的URL
     */
    public String putObject(String bucketName, String fileName, MultipartFile file) {
        // 先创建桶
        this.createBucket(bucketName);

        // 给文件名添加时间戳防止重复
        String objectName = sdf.format(new Date()) + "/" + FileUtil.renFileName(fileName);
        // 开始上传
        this.putMultipartFile(BUCKET_NAME, objectName, file);
        log.info("文件上传成功!");
        return ENDPOINT + "/" + BUCKET_NAME + "/" + objectName;
    }

    /**
     * 上传流到指定的文件桶下
     *
     * @param bucketName  桶名称
     * @param fileName    文件名称, 如果要带文件夹请用 / 分割, 例如 /help/index.html
     * @param stream      文件流
     * @param contentType 文件类型, 例如 image/jpeg: jpg图片格式, 点击查看: <a href="https://www.runoob.com/http/http-content-type.html">图片格式</a>
     * @return 文件对应的URL
     */
    public String putObject(String bucketName, String fileName, InputStream stream, String contentType) {
        // 先创建桶
        this.createBucket(bucketName);
        // 给文件名添加时间戳防止重复
        String objectName = sdf.format(new Date()) + "/" + FileUtil.renFileName(fileName);
        // 开始上传
        this.putInputStream(bucketName, objectName, stream, contentType);
        return ENDPOINT + "/" + bucketName + "/" + objectName;
    }

    /**
     * 上传流到指定的文件桶下
     *
     * @param bucketName  桶名称
     * @param fileName    文件名称, 如果要带文件夹请用 / 分割, 例如 /help/index.html
     * @param bytes       字节
     * @param contentType 文件类型, 例如 image/jpeg: jpg图片格式, 点击查看: <a href="https://www.runoob.com/http/http-content-type.html">图片格式</a>
     * @return 文件对应的URL
     */
    public String putObject(String bucketName, String fileName, byte[] bytes, String contentType) {
        // 先创建桶
        this.createBucket(bucketName);
        // 给文件名添加时间戳防止重复
        String objectName = sdf.format(new Date()) + "/" + FileUtil.renFileName(fileName);
        // 开始上传
        this.putBytes(bucketName, objectName, bytes, contentType);
        return ENDPOINT + "/" + bucketName + "/" + objectName;
    }

    /**
     * 上传File文件到默认桶下
     *
     * @param fileName    文件名
     * @param file        文件
     * @param contentType 文件类型, 例如 image/jpeg: jpg图片格式, 点击查看: <a href="https://www.runoob.com/http/http-content-type.html">图片格式</a>
     * @return 文件对应的URL
     */
    public String putObject(String fileName, File file, String contentType) {

        // 给文件名添加时间戳防止重复
        String objectName = sdf.format(new Date()) + "/" + FileUtil.renFileName(fileName);
        // 开始上传
        this.putFile(BUCKET_NAME, objectName, file, contentType);
        return ENDPOINT + "/" + BUCKET_NAME + "/" + objectName;
    }

    /**
     * 上传File文件
     *
     * @param bucketName  文件桶
     * @param objectName  文件名
     * @param file        文件
     * @param contentType 文件类型, 例如 image/jpeg: jpg图片格式, 点击查看: <a href="https://www.runoob.com/http/http-content-type.html">图片格式</a>
     * @return 文件对应的URL
     */
    public String putObject(String bucketName, String objectName, File file, String contentType) {
        // 先创建桶
        this.createBucket(bucketName);
        // 给文件名添加时间戳防止重复
        String fileName = FileUtil.renFileName(objectName);
        // 开始上传
        this.putFile(bucketName, fileName, file, contentType);
        return ENDPOINT + "/" + bucketName + "/" + fileName;
    }

    /**
     * 判断文件是否存在
     *
     * @param objectName 文件名称, 如果要带文件夹请用 / 分割, 例如 /help/index.html
     * @return true存在, 反之
     */
    public Boolean checkFileIsExist(String objectName) {
        return this.checkFileIsExist(BUCKET_NAME, objectName);
    }

    /**
     * 判断文件夹是否存在
     *
     * @param folderName 文件夹名称
     * @return true存在, 反之
     */
    public Boolean checkFolderIsExist(String folderName) {
        return this.checkFolderIsExist(BUCKET_NAME, folderName);
    }

    /**
     * 判断文件是否存在
     *
     * @param bucketName 桶名称
     * @param objectName 文件名称, 如果要带文件夹请用 / 分割, 例如 /help/index.html
     * @return true存在, 反之
     */
    public Boolean checkFileIsExist(String bucketName, String objectName) {
        try {
            minioClient.statObject(
                    StatObjectArgs.builder().bucket(bucketName).object(objectName).build()
            );
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 判断文件夹是否存在
     *
     * @param bucketName 桶名称
     * @param folderName 文件夹名称
     * @return true存在, 反之
     */
    public Boolean checkFolderIsExist(String bucketName, String folderName) {
        try {
            Iterable<Result<Item>> results = minioClient.listObjects(
                    ListObjectsArgs
                            .builder()
                            .bucket(bucketName)
                            .prefix(folderName)
                            .recursive(false)
                            .build());
            for (Result<Item> result : results) {
                Item item = result.get();
                if (item.isDir() && folderName.equals(item.objectName())) {
                    return true;
                }
            }
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 根据文件全路径获取文件流
     *
     * @param objectName 文件名称
     * @return 文件流
     */
    public InputStream getObject(String objectName) {
        return this.getObject(BUCKET_NAME, objectName);
    }

    /**
     * 根据文件桶和文件全路径获取文件流
     *
     * @param bucketName 桶名称
     * @param objectName 文件名
     * @return 文件流
     */
    public InputStream getObject(String bucketName, String objectName) {
        try {
            return minioClient
                    .getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
        } catch (Exception e) {
            throw new RuntimeException("根据文件名获取流失败!", e);
        }
    }

    /**
     * 根据url获取文件流
     *
     * @param url 文件URL
     * @return 文件流
     */
    public InputStream getObjectByUrl(String url) {
        try {
            return new URL(url).openStream();
        } catch (IOException e) {
            throw new RuntimeException("根据URL获取流失败!", e);
        }
    }

    /**
     * 获取全部bucket
     *
     * @return 所有桶信息
     */
    public List<Bucket> getAllBuckets() {
        try {
            return minioClient.listBuckets();
        } catch (Exception e) {
            throw new RuntimeException("获取全部存储桶失败!", e);
        }
    }

    /**
     * 根据bucketName获取信息
     *
     * @param bucketName bucket名称
     * @return 单个桶信息
     */
    public Optional<Bucket> getBucket(String bucketName) {
        try {
            return minioClient.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
        } catch (Exception e) {
            throw new RuntimeException("根据存储桶名称获取信息失败!", e);
        }
    }

    /**
     * 根据bucketName删除信息
     *
     * @param bucketName bucket名称
     */
    public void removeBucket(String bucketName) {
        try {
            minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            throw new RuntimeException("根据存储桶名称删除桶失败!", e);
        }
    }

    /**
     * 删除文件
     *
     * @param objectName 文件名称
     */
    public boolean removeObject(String objectName) {
        try {
            this.removeObject(BUCKET_NAME, objectName);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 删除文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     */
    public boolean removeObject(String bucketName, String objectName) {
        try {
            minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 上传MultipartFile通用方法
     *
     * @param bucketName 桶名称
     * @param objectName 文件名
     * @param file       文件
     */
    private void putMultipartFile(String bucketName, String objectName, MultipartFile file) {
        InputStream stream = null;
        try {
            stream = file.getInputStream();
        } catch (IOException e) {
            throw new RuntimeException("文件流获取错误", e);
        }
        try {
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .contentType(file.getContentType())
                            .stream(stream, stream.available(), -1)
                            .build()
            );
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("文件流上传错误", e);
        }
    }

    /**
     * 上传InputStream通用方法
     *
     * @param bucketName 桶名称
     * @param objectName 文件名
     * @param stream     文件流
     */
    private void putInputStream(String bucketName, String objectName, InputStream stream, String contentType) {
        try {
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .contentType(contentType)
                            .stream(stream, stream.available(), -1)
                            .build()
            );
        } catch (Exception e) {
            throw new RuntimeException("文件流上传错误", e);
        }
    }

    /**
     * 上传 bytes 通用方法
     *
     * @param bucketName 桶名称
     * @param objectName 文件名
     * @param bytes      字节编码
     */
    private void putBytes(String bucketName, String objectName, byte[] bytes, String contentType) {
        // 字节转文件流
        InputStream stream = new ByteArrayInputStream(bytes);
        try {
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .contentType(contentType)
                            .stream(stream, stream.available(), -1)
                            .build()
            );
        } catch (Exception e) {
            throw new RuntimeException("文件流上传错误", e);
        }
    }

    /**
     * 上传 file 通用方法
     *
     * @param bucketName  桶名称
     * @param objectName  文件名
     * @param file        文件
     * @param contentType 文件类型, 例如 image/jpeg: jpg图片格式, 点击查看: <a href="https://www.runoob.com/http/http-content-type.html">图片格式</a>
     */
    private void putFile(String bucketName, String objectName, File file, String contentType) {
        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .contentType(contentType)
                            .stream(fileInputStream, fileInputStream.available(), -1)
                            .build()
            );
        } catch (Exception e) {
            throw new RuntimeException("文件上传错误", e);
        }
    }


    /**
     * 获取文件信息, 如果抛出异常则说明文件不存在
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @throws Exception <a href="https://docs.minio.io/cn/java-client-api-reference.html#statObject">官方异常信息</a>
     */
    public StatObjectResponse getObjectInfo(String bucketName, String objectName) throws Exception {
        return minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }

    /**
     * 获取文件外链
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param expires    过期时间 <=7
     * @return url
     */
    @SneakyThrows
    public String getObjectURL(String bucketName, String objectName, Integer expires) {
        return getObjectURL(bucketName, objectName, expires, Method.GET);
    }

    /**
     * 获取文件外链
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param expires    过期时间 <=7
     * @return url
     */
    @SneakyThrows
    public String getObjectURL(String bucketName, String objectName, Integer expires, Method method) {
        Boolean aBoolean = checkFileIsExist(bucketName, objectName);
        if (!aBoolean) {
            throw new RuntimeException("文件不存在!");
        }
        IntFunction<Integer> integerIntFunction = (int i) -> Math.min(i, 7);
        return minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .method(method)
                        .bucket(bucketName)
                        .object(objectName)
                        .expiry(integerIntFunction.apply(expires), TimeUnit.HOURS)
                        .build());
    }

    /**
     * 获取文件外链
     *
     * @param objectName 文件名称
     * @param expires    过期时间 <=7
     * @return url
     */
    @SneakyThrows
    public String getObjectURL(String objectName, Integer expires) {
        return getObjectURL(BUCKET_NAME, objectName, expires);
    }

    /**
     * 获取文件外链
     *
     * @param objectName 文件名称
     * @return url
     */
    @SneakyThrows
    public String getObjectURL(String objectName) {
        return getObjectURL(BUCKET_NAME, objectName, 1);
    }

    /**
     * 根据文件前置查询文件
     *
     * @param bucketName bucket名称
     * @param prefix     前缀
     * @param recursive  是否递归查询
     * @return MinioItem 列表
     */
    @SneakyThrows
    public List<Item> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) {
        List<Item> list = new ArrayList<>();
        Iterable<Result<Item>> objectsIterator = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(bucketName).prefix(prefix)
                        .recursive(recursive).build()
        );
        if (objectsIterator != null) {
            for (Result<Item> result : objectsIterator) {
                Item item = result.get();
                list.add(item);
            }
        }
        return list;
    }

}

public class FileUtil {
    /**
     * 生成唯一ID
     *
     * @param objectName 文件名
     * @return 唯一ID
     */
    public static String renFileName(String objectName) {
        //判断文件最后一个点所在的位置
        int lastIndexOf = objectName.lastIndexOf(".");
        if (lastIndexOf == -1) {
            return String.format("%s_%s", objectName, System.currentTimeMillis());
        } else {
            // 获取文件前缀,已最后一个点进行分割
            String filePrefix = objectName.substring(0, objectName.lastIndexOf("."));
            // 获取文件后缀,已最后一个点进行分割
            String fileSuffix = objectName.substring(objectName.lastIndexOf(".") + 1);
            // 组成唯一文件名
            return String.format("%s_%s.%s", filePrefix, System.currentTimeMillis(), fileSuffix);
        }
    }
}
/**
 * Minio Bucket访问策略配置
 * Created by macro on 2020/8/11.
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Builder
public class BucketPolicyConfig {

    private String Version;
    private List<Statement> Statement;

    @Data
    @EqualsAndHashCode(callSuper = false)
    @Builder
    public static class Statement {
        private String Effect;
        private String Principal;
        private String Action;
        private String Resource;

    }
}

MinioController(控制层)

/**
 * MinIO对象存储管理
 */
@Controller
@Slf4j
@RequestMapping("/minio")
public class MinioController{

    @Resource
    private MinioUtils minioUtils;


    /**
     * 文件上传
     *
     * @param file
     * @return
     */
    @PostMapping(value = "/upload")
    @ResponseBody
    public Map<String, String> upload(@RequestPart("file") MultipartFile file) {
        try {
            String url = minioUtils.putObject(file);
            Map<String, String> map = new HashMap<>();
            String fileName = file.getOriginalFilename();
            map.put("fileName", fileName);
            map.put("objName", url);
            return map;
        } catch (Exception e) {
            e.printStackTrace();
            log.info("上传发生错误: {}!", e.getMessage());
            throw e;
        }
    }


    /**
     * 文件删除
     *
     * @param objectName
     * @return
     */
    @PostMapping(value = "/delete")
    @ResponseBody
    public boolean delete(@RequestParam("objectName") String objectName) {
        try {
            minioUtils.removeObject(objectName);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }


    /**
     * 文件预览
     *
     * @param objectName 对象名称
     * @return 文件访问连接
     */
    @GetMapping(value = "/preview")
    @ResponseBody
    public String preview(@RequestParam("objectName") String objectName) {
        Boolean aBoolean = minioUtils.checkFileIsExist(objectName);
        if (!aBoolean) {
            return "文件不存在!";
        }
        return minioUtils.getObjectURL(objectName);
    }

    /**
     * 文件下载
     *
     * @param objectName 对象名称
     * @return 文件流
     */
    @GetMapping(value = "/download")
    @ResponseBody
    public void download(@RequestParam("objectName") String objectName, HttpServletResponse response) throws IOException {
        try {
            Boolean aBoolean = minioUtils.checkFileIsExist(objectName);
            if (!aBoolean) {
                response.setHeader("Content-type", "text/html;charset=UTF-8");
                String data = "文件下载失败";
                OutputStream ps = response.getOutputStream();
                ps.write(data.getBytes(StandardCharsets.UTF_8));
                return;
            }

            InputStream object = minioUtils.getObject(objectName);
            byte[] buf = new byte[1024];
            int length;
            response.reset();
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(objectName.substring(objectName.lastIndexOf("/") + 1), "UTF-8"));
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("UTF-8");
            OutputStream outputStream = response.getOutputStream();
            // 输出文件
            while ((length = object.read(buf)) > 0) {
                outputStream.write(buf, 0, length);
            }
            // 关闭输出流
            outputStream.close();
        } catch (Exception e) {
            response.setHeader("Content-type", "text/html;charset=UTF-8");
            String data = "文件下载失败";
            OutputStream ps = response.getOutputStream();
            ps.write(data.getBytes(StandardCharsets.UTF_8));
        }

    }
}

上传测试
在这里插入图片描述
删除测试
在这里插入图片描述

获取文件/预览地址
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我好帅啊~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值