• 使用MinIO搭建对象存储服务


    1.MinIO是什么?

    • MinIO 是一款高性能、分布式的对象存储系统. 它是一款软件产品, 可以100%的运行在标准硬件。即X86等低成本机器也能够很好的运行MinIO。
    • MinIO与传统的存储和其他的对象存储不同的是:它一开始就针对性能要求更高的私有云标准进行软件架构设计。因为MinIO一开始就只为对象存储而设计。所以他采用了更易用的方式进行设计,它能实现对象存储所需要的全部功能,在性能上也更加强劲,它不会为了更多的业务功能而妥协,失去MinIO的易用性、高效性。 这样的结果所带来的好处是:它能够更简单的实现局有弹性伸缩能力的原生对象存储服务。
    • MinIO在传统对象存储用例(例如辅助存储,灾难恢复和归档)方面表现出色。同时,它在机器学习、大数据、私有云、混合云等方面的存储技术上也独树一帜。当然,也不排除数据分析、高性能应用负载、原生云的支持。

    之前我使用的是阿里云OSS,想了解阿里云OSS的小伙伴参考SpringBoot整合阿里云OSS

    2.我这里使用的是docker安装方式,使用的前提是小伙伴你已经安装好了一个docker了,关于docker的具体使用可以参考docker的具体使用

    image

    3.使用步骤

    (1)下载镜像,下载可能有点慢大家等待一下或者配置一下阿里云镜像加速器

    docker run -d -p 9000:9000 -p 9001:9001 --name minio -e MINIO_ACCESS_KEY=qbb -e MINIO_SECRET_KEY=startqbb -v /opt/minio/data:/data -v /opt/minio/config:/root/.minio minio/minio server /data --console-address ":9000" --address ":9001"

    • MINIO_ACCESS_KEY:指定的是"用户名",可以这么理解,后面我们文件上传需要使用
    • MINIO_SECRET_KEY:指定的是"密码",可以这么理解,后面我们文件上传需要使用

    image

    下载并运行完成

    image

    注意:
    • 有可能下载的过程中会出现如下图,minio容器并没有正常启动
      docker ps -a:查看所有容器
      image

    • 我们可以使用docker logs 容器ID(CONTAINERID)查看一下容器的日志
      image

    • 可以看出数data目录没有权限,执行如下命令在启动试试
      chmod 777 /opt/minio/data:设置目录权限为可读可写可执行
      docker start 容器ID:启动容器
      image

    (2)我们先在浏览器访问一下http://192.168.137.72:9000/

    image

    (3)我们在minio中创建一个bucket

    (4)接下来我们创建一个SpringBoot项目

    image

    (5)导入相关的依赖

    <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.qbb</groupId>
        <artifactId>springboot-minio</artifactId>
        <version>1.0</version>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.3.7.RELEASE</version>
        </parent>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.24</version>
            </dependency>
    
            <!--swagger-->
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>2.7.0</version>
            </dependency>
            <!--swagger ui-->
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger-ui</artifactId>
                <version>2.7.0</version>
            </dependency>
    
            <dependency>
                <groupId>io.minio</groupId>
                <artifactId>minio</artifactId>
                <version>8.3.0</version>
            </dependency>
        </dependencies>
    
    </project>

    (6)修改application.yml配置文件

    server:
      port: 7200
    
    spring:
      application:
        name: minio
    
    app:
      minio:
        endpoint: http://192.168.137.72:9001
        accessKey: qbb
        secretKey: startqbb
        bucket: qbb

    注意:9000是我们浏览器访问控制台的端口,而9001是SDK代码操作的端口

    (7)主启动类

    package com.qbb.minio;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    /**
     * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
     * @version 1.0
     * @date 2022-05-20  15:45
     * @Description:
     */
    @SpringBootApplication
    public class MinioApplication {
        public static void main(String[] args) {
            SpringApplication.run(MinioApplication.class, args);
        }
    }

    (8)这里我配置一个swagger2方便测试,还配置了一个minio的配置类绑定配置文件信息,具体配置如下

    package com.qbb.minio.config;
    
    import com.google.common.base.Predicates;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import springfox.documentation.builders.ApiInfoBuilder;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.service.ApiInfo;
    import springfox.documentation.service.Contact;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    
    /**
     * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
     * @version 1.0
     * @date 2022-05-20  16:23
     * @Description:swagger配置类
     */
    @Configuration
    @EnableSwagger2
    public class Swagger2Config {
    
        @Bean
        public Docket adminApiConfig() {
            return new Docket(DocumentationType.SWAGGER_2)
                    .groupName("minioApi")
                    .apiInfo(adminApiInfo())
                    .select()
                    //只显示admin路径下的页面
                    .paths(Predicates.and(PathSelectors.regex("/minio/.*")))
                    .build();
        }
    
        private ApiInfo adminApiInfo() {
    
            return new ApiInfoBuilder()
                    .title("minio-API文档")
                    .version("1.0")
                    .contact(new Contact("QIUQIU&LL", "https://www.cnblogs.com/qbbit", "startqbb@163.com"))
                    .build();
        }
    }
    
    
    
    package com.qbb.minio.config;
    
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
     * @version 1.0
     * @date 2022-05-20  18:57
     * @Description:
     */
    @ConfigurationProperties(prefix = "app.minio")
    @EnableConfigurationProperties
    @Configuration
    @Data
    public class MinioConfig {
    
        private String endpoint;
        private String accessKey;
        private String secretKey;
        private String bucket;
    }
    

    (9)编写测试代码

    package com.qbb.minio.controller;
    
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
     * @version 1.0
     * @date 2022-05-20  16:23
     * @Description:
     */
    @Api(tags = "minio文件管理")
    @RestController
    @RequestMapping("/minio")
    public class FileController {
    
        @ApiOperation("测试程序")
        @GetMapping("/hello")
        public String hello() {
            return "hello";
        }
    
    }

    image

    (10)接下来我们编写文件上传代码

    package com.qbb.minio.controller;
    
    import com.qbb.minio.config.MinioConfig;
    import io.minio.MinioClient;
    import io.minio.PutObjectOptions;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.multipart.MultipartFile;
    
    import java.io.InputStream;
    import java.util.UUID;
    
    
    /**
     * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
     * @version 1.0
     * @date 2022-05-20  16:23
     * @Description:
     */
    @Api(tags = "minio文件管理")
    @RestController
    @RequestMapping("/minio")
    public class FileController {
    
        @Autowired
        private MinioConfig minioConfig;
    
        @ApiOperation("测试程序")
        @GetMapping("/hello")
        public String hello() {
            return "hello";
        }
    
        @ApiOperation("文件上传")
        @PostMapping("/fileUpload")
        public String fileUpload(MultipartFile file) {
            /**
             * 这里应该放在service层处理的,将上传的文件路径存入数据库,我就不这么麻烦了,直接返回给前端
             */
            String bucket = minioConfig.getBucket();
            String endpoint = minioConfig.getEndpoint();
            String accessKey = minioConfig.getAccessKey();
            String secretKey = minioConfig.getSecretKey();
    
            // 1.获取文件名
            String originalFilename = file.getOriginalFilename();
    
            // 2.修改文件名,防止上传重复文件名,导致文件覆盖
            String fileName = UUID.randomUUID().toString().replace("-", "") + "_" + originalFilename;
            // 文件流
            try (InputStream inputStream = file.getInputStream()) {
                // 3.使用MinIO服务的URL,端口,Access key和Secret key创建一个MinioClient对象
                MinioClient minioClient = new MinioClient(endpoint, accessKey, secretKey);
    
                // 4.检查存储桶是否已经存在
                boolean isExist = minioClient.bucketExists(bucket);
                if (isExist) {
                    System.out.println("Bucket already exists");
                } else {
                    // 不存在则创建一个名为bucket的存储桶,用于存储照片的zip文件。
                    minioClient.makeBucket(bucket);
                }
                // 6.上传参数设置项
                PutObjectOptions options = new PutObjectOptions(inputStream.available(), -1);
    
                // 7.设置此次上传的文件的内容类型
                String contentType = file.getContentType();
                options.setContentType(contentType);
    
                // 8.上传
                minioClient.putObject(bucket, fileName, inputStream, options);
    
                // 9.访问路径
                String url = endpoint + "/" + bucket + "/" + fileName;
                return url;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
    }
    

    (11)使用Swagger测试一下

    image

    (12)结果

    • swagger
      image

    • minio控制台
      image

    (13)删除minio中的文件

     @ApiOperation("删除文件")
        @DeleteMapping("/remove")
        public boolean remove() {
            try {
                // 使用MinIO服务的URL,端口,Access key和Secret key创建一个MinioClient对象
                MinioClient minioClient = new MinioClient(minioConfig.getEndpoint(), minioConfig.getAccessKey(), minioConfig.getSecretKey());
                // 从bucket中删除文件(文件名)。
                minioClient.removeObject(minioConfig.getBucket(), "ed8aa56a8ec640d6a36a271ed4222605_xiaomi.png");
                System.out.println("successfully removed mybucket/myobject");
                return true;
            } catch (Exception e) {
                System.out.println("Error: " + e);
                return false;
            }
        }

    (14)删除后的结果

    • swagger
      image

    • minio控制台
      image

    (15)注意:我们配置完了,启动我们的项目可能会出现这么一个错误,说我们的请求时间与服务器时间相差太大

    image

    (16)解决办法,linux控制台

    yum -y install ntp ntpdate:安装插件工具
    hwclock --systohc:同步时间
    docker restart minio镜像ID:重启镜像

    (17)相关代码已上传GitHub代码仓库,小伙伴们可以参考参考SpringBoot-Minio

    至此SpringBoot整合Minio实现文件上传完成,更多详细的功能配置各位小伙伴可以参考minio官方


    __EOF__

  • 本文作者: QIUQIU&LL
  • 本文链接: https://www.cnblogs.com/qbbit/p/16291701.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    高等数学(第七版)同济大学 习题3-5 个人解答
    获取公众关注链接
    从0搭建夜莺v6基础监控告警系统(三):告警对接企业微信
    BGP——基本概念3(路由聚合)
    实在智能:RPA领域如何使用CRM实现业务精益化管理
    搭建selenium环境
    【机器学习笔记15】多分类混淆矩阵、F1-score指标详解与代码实现(含数据)
    LeetCode54.螺旋矩阵
    Verilog specify 块语句
    vue中响应式的步骤
  • 原文地址:https://www.cnblogs.com/qbbit/p/16291701.html