zoukankan      html  css  js  c++  java
  • Minio-对象存储

    1. 简介

    官方地址

    MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。

    MinIO是一个非常轻量的服务,可以很简单的和其他应用的结合,类似 NodeJS, Redis 或者 MySQL。

    Minio使用纠删码erasure code和校验和checksum来保护数据免受硬件故障和无声数据损坏。 即便您丢失一半数量(N/2)的硬盘,您仍然可以恢复数据。

    想要使数据丢失可恢复, 最少得挂载4块盘或4的倍数。

    1.1 什么是纠删码erasure code?

    纠删码是一种恢复丢失和损坏数据的数学算法, Minio采用Reed-Solomon code将对象拆分成N/2数据和N/2 奇偶校验块。 这就意味着如果是12块盘,一个对象会被分成6个数据块、6个奇偶校验块,你可以丢失任意6块盘(不管其是存放的数据块还是奇偶校验块),你仍可以从剩下的盘中的数据进行恢复。

    其中原数据块和校验块是根据存储类型决定的。存储块设置,默认是原数据块的一半。

    1.2 为什么纠删码有用?

    纠删码的工作原理和RAID或者复制不同,像RAID6可以在损失两块盘的情况下不丢数据,而Minio纠删码可以在丢失一半的盘的情况下,仍可以保证数据安全。 而且Minio纠删码是作用在对象级别,可以一次恢复一个对象,而RAID是作用在卷级别,数据恢复时间很长。 Minio对每个对象单独编码,存储服务一经部署,通常情况下是不需要更换硬盘或者修复。Minio纠删码的设计目标是为了性能和尽可能的使用硬件加速。

    2. 安装

    2.1 docker

    MinIO自定义Access和Secret密钥

    要覆盖MinIO的自动生成的密钥,可以将Access和Secret密钥设为环境变量。 MinIO允许常规字符串作为Access和Secret密钥。

    docker run -p 9000:9000 --name minio1 
      -e "MINIO_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE" 
      -e "MINIO_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" 
      -v /mnt/data:/data 
      -v /mnt/config:/root/.minio 
      minio/minio server /data
    

    2.2 docker-compose

    version: '3.0'
    services:
      minio:
        image: minio/minio
        container_name: minio
        ports:
          - "9000:9000"
        restart: always
        command: server /data
        environment:
          MINIO_ACCESS_KEY: admin
          #大于等于8位
          MINIO_SECRET_KEY: admin123 
        volumes:
          - /Users/ludangxin/usr/local/docker/minio/data:/data # 映射文件路径
    

    2.3 单机多磁盘挂载

    挂载多个冗余盘,防止数据丢失。

    docker run -p 9000:9000 --name minio1 
      -e "MINIO_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE" 
      -e "MINIO_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" 
      -v /mnt/data:/data1 
      -v /mnt/data:/data2 
      -v /mnt/data:/data3 
      -v /mnt/data:/data4 
      -v /mnt/config:/root/.minio 
      minio/minio server /data1 /data2 /data3 /data4 
    

    2.4 分布式部署

    启动一个分布式Minio实例,你只需要把硬盘位置做为参数传给minio server命令即可,然后,你需要在所有其它节点运行同样的命令。

    注意

    • 分布式Minio里所有的节点需要有同样的access秘钥和secret秘钥,这样这些节点才能建立联接。为了实现这个,你需要在执行minio server命令之前,先将access秘钥和secret秘钥export成环境变量。
    • 分布式Minio使用的磁盘里必须是干净的,里面没有数据。
    • 下面示例里的IP仅供示例参考,你需要改成你真实用到的IP和文件夹路径。
    • 分布式Minio里的节点时间差不能超过3秒,你可以使用NTP 来保证时间一致。
    • 在Windows下运行分布式Minio处于实验阶段,请悠着点使用。

    2.4.1 GNU/Linux 和 macOS

    export MINIO_ACCESS_KEY=<ACCESS_KEY>
    export MINIO_SECRET_KEY=<SECRET_KEY>
    minio server http://192.168.1.11/export1 http://192.168.1.12/export2 
                   http://192.168.1.13/export3 http://192.168.1.14/export4 
                   http://192.168.1.15/export5 http://192.168.1.16/export6 
                   http://192.168.1.17/export7 http://192.168.1.18/export8
    

    2.4.2 docker-compose

    部署4个节点,每个节点挂载一个盘。

    version: '3.7'
    services:
      minio:
        image: minio/minio
        volumes:
          # 值需要换成对应节点的
          - /data0:/data0
        ports:
          - 9000:9000
        environment:
          MINIO_ACCESS_KEY: admin
          MINIO_SECRET_KEY: admin123  
        command: minio server http://minio-00/data0 http://minio-01/data1 http://minio-02/data2 http://minio-03/data3
        healthcheck:
          test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
          interval: 30s
          timeout: 20s
          retries: 3
        # 指定当前节点的hostname
        hostname: minio-00
        # ip地址要换成自己的
        extra_hosts:
          - "minio-00:192.168.1.11"
          - "minio-01:192.168.1.12"
          - "minio-02:192.168.1.13"
          - "minio-03:192.168.1.14"
    

    部署4个节点,每个节点四个盘。

    version: '3.7'
    services:
      minio:
        image: minio/minio
        volumes:
          - /data0:/data0
          - /data1:/data1
          - /data2:/data2
          - /data3:/data3
        ports:
          - 9000:9000
        environment:
          MINIO_ACCESS_KEY: admin
          MINIO_SECRET_KEY: admin123  
        command: minio server http://minio-0{0...3}/data{0...3}
        healthcheck:
          test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
          interval: 30s
          timeout: 20s
          retries: 3
        # 指定当前节点的hostname
        hostname: minio-00
        # ip地址要换成自己的
        extra_hosts:
          - "minio-00:192.168.1.11"
          - "minio-01:192.168.1.12"
          - "minio-02:192.168.1.13"
          - "minio-03:192.168.1.14"
    

    2.5 访问测试

    如图:访问localhost:9000,即可访问minio 登陆页面。

    3. quick start

    3.1 项目结构

    ├── pom.xml
    └── src
        └── main
            ├── java
            │   └── com
            │       └── ldx
            │           └── minio
            │               ├── MinioApplication.java  # 启动类
            │               ├── config
            │               │   ├── MinioConfig.java # minio 配置类
            │               │   └── MinioProperties.java # minio 服务参数
            │               ├── controller
            │               │   └── MinioController.java # 测试控制器
            │               ├── test
            │               │   └── FileUploader.java # 测试上传
            │               └── util
            │                   └── MinioUtils.java # 工具类
            └── resources
                └── application.yaml # 服务配置文件
    

    3.2 引入依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
       <modelVersion>4.0.0</modelVersion>
       <parent>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-parent</artifactId>
          <version>2.5.3</version>
          <relativePath/> <!-- lookup parent from repository -->
       </parent>
       <groupId>com.ldx</groupId>
       <artifactId>minio</artifactId>
       <version>0.0.1-SNAPSHOT</version>
       <name>minio</name>
       <description>Demo project for Spring Boot</description>
       <properties>
          <java.version>1.8</java.version>
       </properties>
       <dependencies>
          <!-- springweb 支持 -->
          <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
          </dependency>
          <!-- minio 工具包 -->
          <dependency>
             <groupId>io.minio</groupId>
             <artifactId>minio</artifactId>
             <version>7.0.2</version>
          </dependency>
          <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
             <optional>true</optional>
          </dependency>
       </dependencies>
    
       <build>
          <plugins>
             <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                   <excludes>
                      <exclude>
                         <groupId>org.projectlombok</groupId>
                         <artifactId>lombok</artifactId>
                      </exclude>
                   </excludes>
                </configuration>
             </plugin>
          </plugins>
       </build>
    </project>
    

    3.2 上传测试

    我们先利用测试代码测试一下 minio 附件上传功能。测试代码如下:

    import java.io.IOException;
    import java.security.NoSuchAlgorithmException;
    import java.security.InvalidKeyException;
    import lombok.extern.slf4j.Slf4j;
    import io.minio.MinioClient;
    import io.minio.errors.MinioException;
    
    @Slf4j
    public class FileUploader {
      public static void main(String[] args) throws NoSuchAlgorithmException, IOException, InvalidKeyException {
        try {
          // 使用MinIO服务的URL,端口,Access key和Secret key创建一个MinioClient对象
          MinioClient minioClient = new MinioClient("http://localhost:9000", "admin", "admin123");
    
          // 检查存储桶是否已经存在
          String bucketName = "test";
          boolean isExist = minioClient.bucketExists(bucketName);
          if(isExist) {
            log.info("Bucket already exists.");
          } else {
            // 创建一个名为test的存储桶,用于存储照片的zip文件。
            minioClient.makeBucket(bucketName);
          }
    
          // 使用putObject上传一个文件到存储桶中。
          minioClient.putObject(bucketName,"lion.jpg", "/Users/ludangxin/temp/舞狮.png",null);
          log.info("/Users/ludangxin/temp/舞狮.png is successfully uploaded as lion.jpg to `test` bucket.");
        } catch(MinioException e) {
          log.info("Error occurred: " + e);
        }
      }
    }
    

    直接运行mian方法,运行成功后查看minio ui界面如下。图片上传成功,so easy~

    3.3 application.yaml

    minio:
      endpoint: http://localhost
      port: 9000
      default-bucket-name: ldx
      access-key: admin
      secret-key: admin123
    

    3.4 MinioProperties

    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    
    /**
     * minio 配置属性类
     *
     * @author ludangxin
     * @date 2021/8/17
     */
    @Data
    @ConfigurationProperties(prefix = "minio")
    public class MinioProperties {
       /**
        * 端点
        */
       private String endpoint;
    
       /**
        * 端口
        */
       private Integer port;
    
       /**
        * 默认的桶名称
        */
       private String defaultBucketName;
    
       /**
        * 访问key
        */
       private String accessKey;
    
       /**
        * 密钥
        */
       private String secretKey;
    }
    

    3.5 MinioConfig

    import io.minio.MinioClient;
    import lombok.SneakyThrows;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import java.util.Objects;
    
    /**
     * minio 配置类
     *
     * @author ludangxin
     * @date 2021/8/17
     */
    @Slf4j
    @Configuration
    @EnableConfigurationProperties(MinioProperties.class)
    public class MinioConfig {
    
       @Bean
       @SneakyThrows
       public MinioClient minioClient(MinioProperties minioProperties) {
          MinioClient minioClient = new MinioClient(minioProperties.getEndpoint(), minioProperties.getPort(),
             minioProperties.getAccessKey(), minioProperties.getSecretKey());
          String defaultBucketName = minioProperties.getDefaultBucketName();
    
          if(Objects.nonNull(defaultBucketName)) {
             // 创建默认的bucket
             if(!minioClient.bucketExists(defaultBucketName)) {
                log.info("create default bucket "{}" success", defaultBucketName);
                minioClient.makeBucket(defaultBucketName);
             }
          }
    
          return minioClient;
       }
    }
    

    3.6 MinioController

    import com.ldx.minio.util.MinioUtils;
    import lombok.RequiredArgsConstructor;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.multipart.MultipartFile;
    
    /**
     * minio 控制器
     *
     * @author ludangxin
     * @date 2021/8/18
     */
    @RestController
    @RequestMapping("minio")
    @RequiredArgsConstructor
    public class MinioController {
    
       private final MinioUtils minioUtils;
    
       @GetMapping
       public String getUrl(String fileName) {
          return minioUtils.getFileUrl(fileName);
       }
    
       @PostMapping
       public String upload(MultipartFile file) {
          return minioUtils.upload(file);
       }
      
       @GetMapping("download/{fileName}")
       public void download(@PathVariable String fileName, HttpServletResponse response) {
          minioUtils.download(fileName, response);
       }
    
       @DeleteMapping
       public void del(String fileName) {
          minioUtils.delFile(fileName);
       }
    
    }
    

    3.7 MinioUtils

    package com.ldx.minio.util;
    
    import io.minio.MinioClient;
    import io.minio.PutObjectOptions;
    import io.minio.messages.Bucket;
    import lombok.RequiredArgsConstructor;
    import lombok.SneakyThrows;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.tomcat.util.http.fileupload.FileUtils;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    import org.springframework.web.multipart.MultipartFile;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.nio.charset.StandardCharsets;
    import java.util.List;
    import java.util.Objects;
    
    /**
     * minio 工具类
     *
     * @author ludangxin
     * @date 2021/8/17
     */
    @Slf4j
    @Component
    @RequiredArgsConstructor
    public class MinioUtils {
       @Value("${minio.default-bucket-name}")
       private String defaultBucketName;
    
       private final MinioClient minioClient;
    
       /**
        * 获取全部bucket
        *
        * @return all bucket
        */
       @SneakyThrows
       public List<Bucket> getAllBuckets() {
          return minioClient.listBuckets();
       }
    
       /**
        * 判断 bucket是否存在
        *
        * @param bucketName 桶名称
        * @return true 存在
        */
       @SneakyThrows
       public boolean bucketExists(String bucketName){
          return minioClient.bucketExists(bucketName);
       }
    
       /**
        * 创建 bucket
        *
        * @param bucketName 桶名称
        */
       @SneakyThrows
       public void createBucket(String bucketName){
          boolean isExist = minioClient.bucketExists(bucketName);
          if(!isExist) {
             minioClient.makeBucket(bucketName);
          }
       }
    
       /**
        * 文件上传
        *
        * @param bucketName 桶名称
        * @param fileName 上传后的文件名称
        * @param fileAbsolutePath 文件的绝对路径
        * @return 文件url
        */
       @SneakyThrows
       public String upload(String bucketName, String fileName, String fileAbsolutePath){
          minioClient.putObject(bucketName, fileName, fileAbsolutePath,null);
          return getFileUrl(bucketName, fileName);
       }
    
       /**
        * 文件上传
        *
        * @param fileName 上传后的文件名称
        * @param stream 文件输入流
        * @return 文件url
        */
       @SneakyThrows
       public String upload(String fileName, InputStream stream){
          this.upload(defaultBucketName, fileName, stream);
          return getFileUrl(defaultBucketName, fileName);
       }
    
       /**
        * 文件上传
        *
        * @param file 文件
        * @return 文件url
        */
       public String upload(MultipartFile file) {
          final String fileName = file.getOriginalFilename();
          this.upload(defaultBucketName, file);
          return this.getFileUrl(defaultBucketName, fileName);
       }
    
       /**
        * 文件上传
        *
        * @param bucketName 桶名称
        * @param file 文件
        * @return 文件url
        */
       public String upload(String bucketName, MultipartFile file) {
          InputStream is = null;
          try {
             is = file.getInputStream();
             final String fileName = file.getOriginalFilename();
             this.upload(bucketName, fileName, is);
             return getFileUrl(bucketName, fileName);
          }
          catch(Exception e) {
             log.error(e.getMessage());
          }
          finally {
             try {
                if(Objects.nonNull(is)) {
                   is.close();
                }
             } catch(IOException e) {
                log.error(e.getMessage());
             }
          }
          return null;
       }
    
       /**
        * 文件上传
        *
        * @param bucketName 桶名称
        * @param fileName 上传后的文件名称
        * @param stream 文件输入流
        * @return 文件url
        */
       @SneakyThrows
       public String upload(String bucketName, String fileName, InputStream stream){
          minioClient.putObject(bucketName, fileName, stream, new PutObjectOptions(stream.available(), -1));
          return getFileUrl(bucketName, fileName);
       }
      
       /**
        * 附件下载
        *
        * @param fileName 附件名称
        */
       @SneakyThrows
       public void download(String fileName, HttpServletResponse response) {
          this.download(defaultBucketName, fileName, response);
       }
    
       /**
        * 文件下载
        * 
        * @param bucketName 桶名称
        * @param fileName 文件名称
        */
       public void download(String bucketName, String fileName, HttpServletResponse response) {
          InputStream in = null;
          OutputStream out = null;
          try {
             in = minioClient.getObject(bucketName, fileName);
             int len = 0;
             byte[] buffer = new byte[1024];
             out = response.getOutputStream();
             response.reset();
             response.addHeader("Content-Disposition",
                   " attachment;filename=" + new String(fileName.getBytes(), StandardCharsets.ISO_8859_1));
             response.setContentType("application/octet-stream");
             while ((len = in.read(buffer)) > 0) {
                out.write(buffer, 0, len);
             }
          } catch (Exception e) {
             log.error(e.getMessage());
          } finally {
             if (in != null){
                try {
                   in.close();
                } catch (Exception e) {
                   log.error(e.getMessage());
                }
             }
             if (out != null) {
                try {
                   out.close();
                } catch (IOException e) {
                   log.error(e.getMessage());
                }
             }
          }
       }
    
       /**
        * 删除文件
        *
        * @param fileName 文件名称
        */
       @SneakyThrows
       public void delFile(String fileName){
          this.delFile(defaultBucketName, fileName);
       }
    
       /**
        * 删除文件
        *
        * @param bucketName 桶名称
        * @param fileName 文件名称
        */
       @SneakyThrows
       public void delFile(String bucketName, String fileName){
          minioClient.removeObject(bucketName, fileName);
       }
    
       /**
        * 获取minio文件的下载地址
        *
        * @param fileName 文件名
        */
       @SneakyThrows
       public String getFileUrl(String fileName) {
          return this.getFileUrl(defaultBucketName, fileName);
       }
    
       /**
        * 获取minio文件的下载地址
        *
        * @param bucketName 桶名称
        * @param fileName 文件名
        */
       @SneakyThrows
       public String getFileUrl(String bucketName, String fileName) {
          return minioClient.presignedGetObject(bucketName, fileName);
       }
    
       /**
        * 设置桶策略
        *
        * @param bucketName 桶名称
        * @param policy 策略
        */
       @SneakyThrows
       public void setBucketPolicy(String bucketName, String policy) {
          minioClient.setBucketPolicy(bucketName, policy);
       }
    
    }
    

    4. 最新版本工具包

    在当前最新的jar中(8.3.0),minio 工具类的使用方法跟7.0.2版本还是有很大出入的,在这里记录一下。

    4.1 MinioConfig

    import io.minio.BucketExistsArgs;
    import io.minio.MakeBucketArgs;
    import io.minio.MinioClient;
    import lombok.SneakyThrows;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import java.util.Objects;
    
    /**
     * minio 配置类
     *
     * @author ludangxin
     * @date 2021/8/17
     */
    @Slf4j
    @Configuration
    @EnableConfigurationProperties(MinioProperties.class)
    public class MinioConfig {
    
       @Bean
       @SneakyThrows
       public MinioClient minioClient(MinioProperties minioProperties) {
          MinioClient minioClient = MinioClient.builder()
             .endpoint(minioProperties.getEndpoint(), minioProperties.getPort(), false)
             .credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
             .build();
          String defaultBucketName = minioProperties.getDefaultBucketName();
    
          if(Objects.nonNull(defaultBucketName)) {
             BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder()
                .bucket(defaultBucketName)
                .build();
             // 创建默认的bucket
             if(!minioClient.bucketExists(bucketExistsArgs)) {
                MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder()
                   .bucket(defaultBucketName)
                   .build();
                minioClient.makeBucket(makeBucketArgs);
                log.info("create default bucket "{}" success", defaultBucketName);
             }
          }
    
          return minioClient;
       }
    }
    

    4.2 MinioUtils

    import io.minio.*;
    import io.minio.http.Method;
    import io.minio.messages.Bucket;
    import lombok.RequiredArgsConstructor;
    import lombok.SneakyThrows;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    import org.springframework.web.multipart.MultipartFile;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.nio.charset.StandardCharsets;
    import java.util.List;
    import java.util.Objects;
    import java.util.concurrent.TimeUnit;
    
    /**
     * minio 工具类
     *
     * @author ludangxin
     * @date 2021/8/17
     */
    @Slf4j
    @Component
    @RequiredArgsConstructor
    public class MinioUtils {
       @Value("${minio.default-bucket-name}")
       private String defaultBucketName;
    
       private final MinioClient minioClient;
    
       /**
        * 获取全部bucket
        *
        * @return all bucket
        */
       @SneakyThrows
       public List<Bucket> getAllBuckets() {
          return minioClient.listBuckets();
       }
    
       /**
        * 判断 bucket是否存在
        *
        * @param bucketName 桶名称
        * @return true 存在
        */
       @SneakyThrows
       public boolean bucketExists(String bucketName){
          BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder()
                .bucket(bucketName)
                .build();
          return minioClient.bucketExists(bucketExistsArgs);
       }
    
       /**
        * 创建 bucket
        *
        * @param bucketName 桶名称
        */
       @SneakyThrows
       public void createBucket(String bucketName){
          boolean isExist = this.bucketExists(bucketName);
          if(!isExist) {
             MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder()
                   .bucket(bucketName)
                   .build();
             minioClient.makeBucket(makeBucketArgs);
          }
       }
    
       /**
        * 文件上传
        *
        * @param bucketName 桶名称
        * @param fileName 上传后的文件名称
        * @param fileAbsolutePath 文件的绝对路径
        * @return 文件url
        */
       @SneakyThrows
       public ObjectWriteResponse upload(String bucketName, String fileName, String fileAbsolutePath){
          UploadObjectArgs uploadObjectArgs = UploadObjectArgs.builder()
                .bucket(bucketName)
                .filename(fileAbsolutePath)
                .object(fileName)
                .build();
          return minioClient.uploadObject(uploadObjectArgs);
       }
    
       /**
        * 文件上传
        *
        * @param fileName 上传后的文件名称
        * @param stream 文件输入流
        * @return 文件url
        */
       @SneakyThrows
       public String upload(String fileName, InputStream stream){
          this.upload(defaultBucketName, fileName, stream);
          return getFileUrl(defaultBucketName, fileName);
       }
    
       /**
        * 文件上传
        *
        * @param bucketName 桶名称
        * @param fileName 上传后的文件名称
        * @param stream 文件输入流
        * @return 文件url
        */
       @SneakyThrows
       public ObjectWriteResponse upload(String bucketName, String fileName, InputStream stream){
          try {
             PutObjectArgs objectArgs = PutObjectArgs.builder()
                   .bucket(bucketName)
                   .object(fileName)
                   .stream(stream, stream.available(), -1)
                   .build();
             return minioClient.putObject(objectArgs);
          }
          catch(Exception e) {
             log.error(e.getMessage());
          }
          finally {
             try {
                if(Objects.nonNull(stream)) {
                   stream.close();
                }
             } catch(IOException e) {
                log.error(e.getMessage());
             }
          }
          return null;
       }
    
       /**
        * 文件上传
        *
        * @param file 文件
        * @return 文件url
        */
       public ObjectWriteResponse upload(MultipartFile file) {
          return this.upload(defaultBucketName, file);
       }
    
       /**
        * 文件上传
        *
        * @param bucketName 桶名称
        * @param file 文件
        * @return 文件url
        */
       public ObjectWriteResponse upload(String bucketName, MultipartFile file) {
          InputStream is = null;
          try {
             is = file.getInputStream();
             final String fileName = file.getOriginalFilename();
             String contentType = file.getContentType();
             PutObjectArgs objectArgs = PutObjectArgs.builder()
                .bucket(bucketName)
                .object(fileName)
                .stream(is, is.available(), -1)
                .contentType(contentType)
                .build();
             return minioClient.putObject(objectArgs);
          }
          catch(Exception e) {
             log.error(e.getMessage());
          }
          finally {
             try {
                if(Objects.nonNull(is)) {
                   is.close();
                }
             } catch(IOException e) {
                log.error(e.getMessage());
             }
          }
          return null;
       }
    
       /**
        * 附件下载
        *
        * @param fileName 附件名称
        */
       @SneakyThrows
       public void download(String fileName, HttpServletResponse response) {
          this.download(defaultBucketName, fileName, response);
       }
    
       /**
        * 附件下载
        *
        * @param bucketName 桶名称
        * @param fileName 附件名称
        */
       @SneakyThrows
       public void download(String bucketName, String fileName, HttpServletResponse response) {
          GetObjectArgs build = GetObjectArgs.builder().bucket(bucketName).object(fileName).build();
          OutputStream out = null;
          try(GetObjectResponse object = minioClient.getObject(build)) {
             int len = 0;
             byte[] buffer = new byte[1024];
             out = response.getOutputStream();
             response.reset();
             String fileName1 = new String(fileName.getBytes(), StandardCharsets.ISO_8859_1);
             response.addHeader("Content-Disposition", " attachment;filename=" + fileName1);
             response.setContentType("application/octet-stream");
    
             while((len = object.read(buffer)) > 0) {
                out.write(buffer, 0, len);
             }
          } catch(Exception e) {
             log.error(e.getMessage());
          } finally {
             if(out != null) {
                try {
                   out.close();
                } catch(IOException e) {
                   log.error(e.getMessage());
                }
             }
          }
       }
    
       /**
        * 附件下载
        *
        * @param fileName 附件名称
        */
       @SneakyThrows
       public void download(String bucketName, String fileName, String fileAbsolutePath) {
          DownloadObjectArgs downloadObjectArgs = DownloadObjectArgs.builder()
             .bucket(bucketName)
             .object(fileName)
             .filename(fileAbsolutePath)
             .build();
          minioClient.downloadObject(downloadObjectArgs);
       }
    
       /**
        * 删除文件
        *
        * @param fileName 文件名称
        */
       @SneakyThrows
       public void delFile(String fileName){
          this.delFile(defaultBucketName, fileName);
       }
    
       /**
        * 删除文件
        *
        * @param bucketName 桶名称
        * @param fileName 文件名称
        */
       @SneakyThrows
       public void delFile(String bucketName, String fileName){
          RemoveObjectArgs removeObjectsArgs = RemoveObjectArgs.builder()
                .bucket(bucketName)
                .object(fileName)
                .build();
          minioClient.removeObject(removeObjectsArgs);
       }
    
       /**
        * 获取minio文件的下载地址
        *
        * @param fileName 文件名
        */
       @SneakyThrows
       public String getFileUrl(String fileName) {
          return this.getFileUrl(defaultBucketName, fileName);
       }
    
       /**
        * 获取minio文件的下载地址
        *
        * @param bucketName 桶名称
        * @param fileName 文件名
        */
       @SneakyThrows
       public String getFileUrl(String bucketName, String fileName) {
          GetPresignedObjectUrlArgs objectUrlArgs = GetPresignedObjectUrlArgs.builder()
                .method(Method.GET)
                .bucket(bucketName)
                .object(fileName)
                .build();
          return minioClient.getPresignedObjectUrl(objectUrlArgs);
       }
    
       /**
        * 获取minio文件的下载地址
        *
        * @param fileName 文件名
        */
       @SneakyThrows
       public String getFileUrl(String fileName, Integer duration, TimeUnit unit) {
          return this.getFileUrl(defaultBucketName, fileName, duration, unit);
       }
    
       /**
        * 获取minio文件的下载地址
        *
        * @param bucketName 桶名称
        * @param fileName 文件名
        */
       @SneakyThrows
       public String getFileUrl(String bucketName, String fileName, Integer duration, TimeUnit unit) {
          GetPresignedObjectUrlArgs objectUrlArgs = GetPresignedObjectUrlArgs.builder()
                .method(Method.GET)
                .bucket(bucketName)
                .object(fileName)
                .expiry(duration, unit)
                .build();
          return minioClient.getPresignedObjectUrl(objectUrlArgs);
       }
    
       /**
        * 设置桶策略
        *
        * @param bucketName 桶名称
        * @param policy 策略
        */
       @SneakyThrows
       public void setBucketPolicy(String bucketName, String policy) {
          SetBucketPolicyArgs bucketPolicyArgs = SetBucketPolicyArgs.builder()
                .bucket(bucketName)
                .config(policy)
                .build();
          minioClient.setBucketPolicy(bucketPolicyArgs);
       }
    
    }
    
    

    4.3 测试类

    package com.ldx.minio.controller;
    
    import com.ldx.minio.util.MinioUtils;
    import io.minio.ObjectWriteResponse;
    import lombok.RequiredArgsConstructor;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.multipart.MultipartFile;
    import javax.servlet.http.HttpServletResponse;
    
    
    /**
     * minio 控制器
     *
     * @author ludangxin
     * @date 2021/8/18
     */
    @RestController
    @RequestMapping("minio")
    @RequiredArgsConstructor
    public class MinioController {
    
       private final MinioUtils minioUtils;
    
       @GetMapping
       public String getUrl(String fileName) {
          return minioUtils.getFileUrl(fileName);
       }
    
       @PostMapping
       public ObjectWriteResponse upload(MultipartFile file) {
          return minioUtils.upload(file);
       }
    
       @GetMapping("download/{fileName}")
       public void download(@PathVariable String fileName, HttpServletResponse response) {
          minioUtils.download(fileName, response);
       }
    
       @GetMapping("download/{bucketName}/{fileName}")
       public void download(@PathVariable String bucketName, @PathVariable String fileName) {
          minioUtils.download(bucketName, fileName, "/Users/ludangxin/temp/" + fileName);
       }
    
       @DeleteMapping
       public void del(String fileName) {
          minioUtils.delFile(fileName);
       }
    
    }
    
  • 相关阅读:
    freebsd ports update url
    Cisco交换机里IP和MAC地址互查找出对应端口
    实现不同vlan间的相互通信方法一:单臂路由
    文件共享③Samba实例
    RHEL6基础四十九之RHEL文件(夹)权限进阶篇
    windows下查找指定端口被哪个程序占用
    DNSmasq – 配置DNS和DHCP
    dnsmasq多vlan配置
    dnsmasq.conf 配置
    windows2003 DHCP中批处理绑定IP与MAC
  • 原文地址:https://www.cnblogs.com/ludangxin/p/15178147.html
Copyright © 2011-2022 走看看