springcloud:对象存储组件MinIO(十六)

0. 引言

在实际开发中,我们经常会面临需要存储文档、存储图片等文件存储需求,并且在分布式架构下,文件又需要实现各节点共享,类似于共享文件夹类的需求,在分布式服务器中创建共享文件夹成本较大,甚至当需要跨机房访问时就不满足了,此时我们需要一个第三方的组件,来实现这类对象存储

也就出现了OSS、OBS、minIO、hdfs这类对象存储组件,今天,我们主要来学习免费开源的MinIO组件

1. minio简介

MinIO是一个使用go语言开发的,开源的对象存储组件,能够提供高性能、高可用的数据存储能力,支持分布式部署,提供数据加密、访问控制、版本控制、生命周期管理和事件通知等功能。它还支持高级特性,如分片上传和分片下载,以提高大文件的处理效率。

官方文档:https://www.minio.org.cn/

在这里插入图片描述

2. minio安装

minio支持docker安装,压缩包安装,这里我们为了安装方便,采用docker安装,如果使用的是mac,也可以使用brew工具安装,具体可参考官网文档:https://github.com/minio/minio

1、下载镜像

docker pull minio/minio

2、创建数据映射目录

mkdir -p /Library/software/dockerdata/minio/data

3、创建容器

注意这里我安装的版本是RELEASE.2023-01-02T09-40-09Z

docker run -p 9000:9000 -p 9090:9090 \
 --name minio \
 -e "MINIO_ACCESS_KEY=minioadmin" \
 -e "MINIO_SECRET_KEY=minioadmin" \
 -v /Library/software/dockerdata/minio/data:/data \
 minio/minio server \
 /data --console-address ":9090" -address ":9000"

4、登陆 localhost:9090,输入账号/密码: minioadmin / minioadmin
在这里插入图片描述

3. minio管理端介绍

管理端默认通过9090端口进入:http://ip:9090/

其中比较常用的菜单包括:

  • Object Browser: 对象管理页面,minio中所有的桶和桶中的文件都可以在这个页面查看,这里的桶 bucket,大家可以简单的理解为文件夹
    在这里插入图片描述- Buckets: 桶管理页面,用于管理桶相关的配置,比如桶的访问权限、桶的生命周期(桶中文件保留几天)
    在这里插入图片描述
  • Identity: 权限管理页面,可以创建用户、分组,并设置对应权限等
    在这里插入图片描述
  • Monitoring: 监控页面,监控显示minio的各类健康、状态、日志信息
    在这里插入图片描述

4. minio客户端使用

1、添加pom依赖

<dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.5.3</version>
</dependency>

<dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.10.0</version>
</dependency>

2、增加配置文件

minio:
  # minio地址
  endpoint: http://localhost:9000
  # 账户
  username: minioadmin
  # 密码
  password: minioadmin
  defaultBucketName: test

3、创建配置类,用于生成MinioClient

/**
 * @author benjamin_5
 * @Description minio配置类
 * @date 2023/8/5
 */
@Configuration
public class MinioConfig {
    
    

    @Value("${minio.endpoint}")
    private String endpoint;

    @Value("${minio.username}")
    private String username;

    @Value("${minio.password}")
    private String password;

    @Value("${minio.defaultBucketName}")
    private String defaultBucketName;

    @Bean
    public MinioClient minioClient(){
    
    
        return MinioClient.builder().credentials(username, password).endpoint(endpoint).build();
    }

}

4、创建一个返回实体类,方便规范返回信息

@Data
public class MinioReturn {
    
    

    /**
     * 文件地址
     */
    private String path;

    /**
     * 原始文件名
     */
    private String inputName;

    /**
     * 最终文件名
     */
    private String outPutName;

}

5、创建MinioTemplate类,用来书写minio工具类

@Component
public class MinioTemplate {
    
    

    @Autowired
    private MinioClient minioClient;

    private static final String SLASH = "/";

    @Value("${minio.defaultBucketName}")
    private String defaultBucketName;

    @Value("${minio.endpoint}")
    private String endpoint;

    /**
     * 创建桶
     *
     * @param bucketName
     * @throws Exception
     */
    public void makeBucket(String bucketName) throws Exception {
    
    
        BucketExistsArgs args = BucketExistsArgs.builder().bucket(bucketName).build();
        if (!minioClient.bucketExists(args)) {
    
    
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     * 上传文件
     *
     * @param file
     * @return
     * @throws Exception
     */
    public MinioReturn putFile(MultipartFile file) throws Exception {
    
    
        return putFile(file, file.getOriginalFilename(), defaultBucketName);
    }

    public MinioReturn putFile(MultipartFile file, String fileName, String bucketName) throws Exception {
    
    
        if (bucketName == null || bucketName.length() == 0) {
    
    
            bucketName = defaultBucketName;
        }
        makeBucket(bucketName);
        minioClient.putObject(PutObjectArgs.builder()
                .bucket(bucketName)
                .object(fileName)
                .stream(file.getInputStream(), file.getSize(), -1)
                .contentType(file.getContentType())
                .build());
        return new MinioReturn(fileLink(bucketName, fileName), file.getOriginalFilename(), fileName);
    }

    /**
     * 删除文件
     *
     * @param bucketName
     * @param fileName
     * @throws Exception
     */
    public void removeFile(String bucketName, String fileName) throws Exception {
    
    
        minioClient.removeObject(RemoveObjectArgs.builder()
                .bucket(bucketName == null || bucketName.length() == 0 ? defaultBucketName : bucketName)
                .object(fileName)
                .build());
    }

    @SneakyThrows
    private String fileLink(String bucketName, String fileName) {
    
    
        return endpoint.concat(SLASH).concat(bucketName).concat(SLASH).concat(fileName);
    }

    private String getFileName(String fileName) {
    
    
        return getFileName(null, fileName);
    }

    private String getFileName(String prefix, String fileName) {
    
    
        String fileNamePre = fileName;
        String fileType = "";
        int index = fileName.lastIndexOf(".");
        if (index > 0) {
    
    
            fileNamePre = fileName.substring(0, index);
            fileType = fileName.substring(index);
        }
        String name = UUID.randomUUID().toString().replace("-", "");
        if (!org.springframework.util.StringUtils.isEmpty(fileNamePre)) {
    
    
            name = fileNamePre + "-" + name + fileType;
        }
        if (!StringUtils.isEmpty(prefix)) {
    
    
            name = prefix + "-" + name;
        }
        return name;
    }


}

6、书写控制类,用于测试

@RestController
@RequestMapping("minio")
@AllArgsConstructor
public class MinioController {
    
    

    private final MinioTemplate minioTemplate;

    @PostMapping("/upload")
    @ResponseBody
    public MinioReturn upload(MultipartFile file) throws Exception {
    
    
        return minioTemplate.putFile(file);
    }

    @PostMapping("/remove")
    @ResponseBody
    public String remove(String fileName, String bucketName) throws Exception{
    
    
        minioTemplate.removeFile(bucketName, fileName);
        return "success";
    }

}

7、调用上传接口,如下图所示,调用成功

在这里插入图片描述
我们查看minio中,自动创建了桶,并且文件也上传成功了

在这里插入图片描述
同样再测试一下删除接口

在这里插入图片描述
查看minio中删除成功

在这里插入图片描述

5. 应用场景

    1. 静态资源存储

如在官网、门户、首页等网站,我们经常需要加载一些静态资源,如图片、js文件、视频文件等,一些我们可以直接存放到nginx加载,另一方面我们也可以存放到minio中,通过minio进行访问

要通过minio访问的前提是记得把桶权限设置为public

在这里插入图片描述
上述代码创建的桶默认是private的,如果想要通过客户端代码调整桶权限的话,可以通过minioClient.setBucketPolicy方法,设置完后可以通过返回的地址进行访问,如下所示(如果想要通过外网访问,给对应的内网地址端口做个外网映射即可)

在这里插入图片描述

开启权限public会有个安全问题,那就是当你访问桶路径时,会发现会把所有桶下的文件列出来,这样只要再拼接上文件名就能访问所有文件了

在这里插入图片描述

要解决这个问题,只需要将权限设置为custom,然后将"s3:ListBucket"取消即可

在这里插入图片描述
再次访问会发现权限禁止,而加上文件名后是可以正常查看的
在这里插入图片描述

当然如果在旧版本中是不支持直接在minio管理页面中直接设置的,你可以通过下载s3browser https://s3browser.com/,连接上minio后,右键在Edit Bucket Policy中设置

在这里插入图片描述

    1. 文件暂存

某些时候,涉及组件或系统间传输文件时,直接通过接口传输效率太慢且及时性不足,或者用户其实收到后不需要马上查看这些文件,这时我们就可以把文件暂存到minio中,发送一个文件地址给客户,客户收到这个地址可以再进行下载。
既然是文件暂存,那么就希望能自动删除,实现自动删除有两种方法,一种是通过书写shell脚本,直接删除指定路径下的文件,minio在服务器上存储的文件就是直接放在文件夹下,没有特殊处理,所以直接删除即可,第二种就是使用minio提供的生命周期管理,在Buckets-Lifecycle中可以设置,同时这个也可以在客户端中创建桶时就设置,通过minioClient.setBucketLifecycle();方法

在这里插入图片描述

    1. 解放带宽压力

某些时候,涉及接口文件传输时,直接传输占用大量带宽,导致并发上不去,而客户可能也不需要马上使用到传输的文件,只是需要马上知道一个状态或者其他信息,这时就可以通过将文件上传到minio, 而发送一个文件地址给客户,这样将文件状态通知和下载分步进行。
这里某的同学可能会想,下载不还是要占用带宽吗,怎么说是节约带宽资源呢,这是因为一般接口调用追求耗时,我们一般会把接口服务的带宽部署为性能更高的,价格自然更贵,而文件下载服务的没有那么高的延迟要求,就单独拉一根性能相对没那么强的,也就更便宜的,这样自然减少了带宽费用

6. 总结

至此,我们针对minio的快速上手就完成了, 文中只是描述了minio最常用的方法,还有更多方法、指令等待大家自己探索学习。

文中演示源码见如下地址:https://gitee.com/wuhanxue/wu_study/tree/master/demo/minio_demo

猜你喜欢

转载自blog.csdn.net/qq_24950043/article/details/128596068