类似于FastDFS/HDFS的一个文件存储服务!
SpringBoot整合MinIO实现分布式文件服务!
#MinIO简介?
Minio 是个基于 Golang 编写的开源对象存储套件,基于Apache License v2.0开源协议,虽然轻量,却拥有着不错的性能。它兼容亚马逊S3云存储服务接口。可以很简单的和其他应用结合使用,例如 NodeJS、Redis、MySQL等。
#1. 应用场景
MinIO 的应用场景除了可以作为私有云的对象存储服务来使用,也可以作为云对象存储的网关层,无缝对接 Amazon S3 或者 MicroSoft Azure
#2. 特点
-
高性能:作为一款高性能存储,在标准硬件条件下,其读写速率分别可以达到 55Gb/s 和 35Gb/s。并且MinIO 支持一个对象文件可以是任意大小,从几kb到最大5T不等。
-
可扩展:不同MinIO集群可以组成联邦,并形成一个全局的命名空间,并且支持跨越多个数据中心。
-
云原生:容器化、基于K8S的编排、多租户支持。
-
Amazon S3兼容:使用 Amazon S3 v2 / v4 API。可以使用Minio SDK,Minio Client,AWS SDK 和 AWS CLI 访问Minio服务器。
-
SDK支持:
-
GO SDK:GitHub - minio/minio-go: MinIO Go client SDK for S3 compatible object storage(opens new window)
-
JavaSDK:GitHub - minio/minio-java: MinIO Client SDK for Java(opens new window)
-
PythonSDK:GitHub - minio/minio-py: MinIO Client SDK for Python(opens new window)
-
-
图形化界面:有操作页面
-
支持纠删码:MinIO使用纠删码、Checksum来防止硬件错误和静默数据污染。在最高冗余度配置下,即使丢失1/2的磁盘也能恢复数据。
功能很强大~
源码地址:GitHub - minio/minio: High Performance Object Storage for AI(opens new window)
中文文档地址:MinIO | 高性能, Kubernetes原生对象存储(opens new window)
#安装MinIO
安装非常简单,这里使用docker安装,步骤如下:
#1. 获取镜像
执行命令如下:
docker pull minio/minio
#2. 启动镜像
执行命令如下:
mkdir -p /opt/mnt/data /opt/mnt/conf
docker run -p 9000:9000 -p 9099:9099 --name minio -d --restart=always -e "MINIO_ACCESS_KEY=admin" -e "MINIO_SECRET_KEY=admin123456789" -v /opt/mnt/data:/data -v /opt/mnt/config:/root/.minio minio/minio server --console-address ":9000" --address ":9099" /data
命令解释如下:
-
-p:9000是图形界面的端口,9001是API的端口,在使用SDK连接需要用到
-
MINIO_ACCESS_KEY:指定图形界面的用户名
-
MINIO_SECRET_KEY:指定图形界面的密码
按照上述两个步骤启动成功即可。
注意:ACCESS_KEY 长度最少3个字符,SECRET_KEY 长度最少8个字符
#3. 图形界面操作
安装成功后直接访问地址:http:/ip:9000/login,如下:
输入用户名和密码登录成功后,如下:
菜单很多,这里就不再详细介绍了,笔者这里直接在Buckets菜单中创建一个桶为test,如下图:
并且设置这个桶的隐私规则为public,如下:
MinIO到此已经安装设置成功了
#SpringBoot整合MinIO上传文件
要实现SDK上传需要检查存放图片data文件是否为最高权限,不然上传接口会报错:
S3 API Requests must be made to API port
原因:权限不够不能创建对应文件路径
解决方案:
检查docker映射的data目录 /opt/mnt/data权限,如果权限不够 chmod 777 /opt/mnt/data
虽然MinIO在图形界面提供了手动上传的操作,但是也可以通过SDK的方式去上传,下面介绍一下Spring Boot 整合MinIO上传文件。
#1. 获取accessKey和secretKey
这里的accessKey和secretKey并不是图形界面登录名和密码,获取很简单,直接在图形界面中操作,如下图:
#2. 添加依赖
添加MinIO的依赖,如下:
<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>
#3. 添加配置
minio:# minio地址endpoint: http://localhost:9000# 账户username: minioadmin# 密码password: minioadmindefaultBucketName: test
#4. 创建配置类,用于生成MinioClient
/*** @Description minio配置类*/
@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;@Beanpublic MinioClient minioClient(){return MinioClient.builder().credentials(username, password).endpoint(endpoint).build();}}
#5.创建一个返回实体类,方便规范返回信息
@Data
public class MinioReturn {/*** 文件地址*/private String path;/*** 原始文件名*/private String inputName;/*** 最终文件名*/private String outPutName;}
#6.创建MinioTemplate
类,用来书写minio工具类
@Component
public class MinioTemplate {@Autowiredprivate 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());}@SneakyThrowsprivate 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;}}
#7.书写控制类,用于测试
@RestController
@RequestMapping("minio")
@AllArgsConstructor
public class MinioController {private final MinioTemplate minioTemplate;@PostMapping("/upload")@ResponseBodypublic MinioReturn upload(MultipartFile file) throws Exception {return minioTemplate.putFile(file);}@PostMapping("/remove")@ResponseBodypublic String remove(String fileName, String bucketName) throws Exception{minioTemplate.removeFile(bucketName, fileName);return "success";}}
#8. 测试
我们查看minio中,自动创建了桶,并且文件也上传成功了
同样再测试一下删除接口
查看minio中删除成功
如果想通过配置域名映射minio服务器访问指定图片:
桶权限设置为public
上述代码创建的桶默认是private
的,如果想要通过客户端代码调整桶权限的话,可以通过minioClient.setBucketPolicy
方法,设置完后可以通过返回的地址进行访问,如下所示(如果想要通过外网访问,给对应的内网地址端口做个外网映射即可)
开启权限public会有个安全问题,那就是当你访问桶路径时,会发现会把所有桶下的文件列出来,这样只要再拼接上文件名就能访问所有文件了
要解决这个问题,只需要将权限设置为custom
,然后将"s3:ListBucket"
取消即可
再次访问会发现权限禁止,而加上文件名后是可以正常查看的
当然,也可以使用AmazonS3 云存储服务接口
相关文档:Amazon S3对象执行操作 - AWS SDK for Java1.x