目录
开始
Docker 部署
MinIO 中的基本概念
SpringBoot 集成 MinIO
依赖
配置
MinIO 时间差问题报错 The difference between the request time and the server`s time is too large
MinIO 中对 Bucket(文件夹) 的操作
是否存在 / 创建
查询所有文件夹
删除文件夹
MinIO 中对 Object(文件) 的操作
两种文件上传的方式
查看文件状态(是否存在)
生成带签名的URL路径
怎么使用不带签名的 url 直接访问
从 MinIO 上获取图片,然后下载到本地磁盘'
获取文件夹下的所有文件
开始
Docker 部署
a)拉取镜像
docker pull minio/minio
b)创建挂载点
mkdir -p ~/env/minio/conf
mkdir -p ~/env/minio/data
c)运行
这里设置了 MinIO 的用户名和密码,注意密码不能少于 8 位
docker run -d \
--name minio \
-p 9000:9000 \
-p 9001:9001 \
--privileged=true \
-e "MINIO_ROOT_USER=root" \
-e "MINIO_ROOT_PASSWORD=rootroot" \
-v ~/env/minio/data:/data \
-v ~/env/minio/conf:/root/.minio \
minio/minio server \
--console-address ":9000" \
--address ":9001" /data
d)访问:http://env-base:9000
MinIO 中的基本概念
Bucket:相当于存放文件的文件夹,用来存储 Object 的逻辑空间.
Object:相当于文件,是存储到 MinIO 中的基本对象.
Ps:Minio 存在线程安全问题么?
Minio 是线程安全的,即使在 SpringBoot 中 Bean 是使用单例模式的(作者在 github 上的回复).
SpringBoot 集成 MinIO
依赖
Note:官网地址 Software Development Kits (SDK) — MinIO Object Storage for Linux
Maven 如下
<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.11</version>
</dependency>
Gradle 如下
dependencies {implementation("io.minio:minio:8.5.11")
}
配置
由于 MinIO 没有 SpringBootStarter 相关的依赖,因此配置类需要我们自己来写~
import io.minio.MinioClient
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration@Configuration
class MinioConfig {@Beanfun minioClient(): MinioClient = MinioClient.builder().endpoint("http://100.105.180.32:9001") //格式必须是 http://ip:port 注意: 这里使用的 9001 端口,而不是 9000.credentials("root", "rootroot") //用户名 和 密码.build()}
MinIO 时间差问题报错 The difference between the request time and the server`s time is too large
如果出现了上述报错,说明你的主机和服务器上的时间不一致.
解决如下:
a)下载 ntpdate,用来同步主机和服务器的时间.
yum install ntpdate -y
b)同步时间,如下命令
ntpdate pool.ntp.org
MinIO 中对 Bucket(文件夹) 的操作
是否存在 / 创建
案例:如果不存在 dir1 文件夹,就创建.
@SpringBootTest
class MinioApplicationTests {@Resourceprivate lateinit var minioClient: MinioClient/*** 如果文件夹 dir1 不存在就创建*/@Testfun test1() {val exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket("dir1").build())if (!exists) {minioClient.makeBucket(MakeBucketArgs.builder().bucket("dir1").build())} else {println("文件夹已经存在!")}}}
第一次运行,可以看到会创建出这个文件夹:
第二次运行就会进行提示:
查询所有文件夹
如下代码:
@Testfun test2() {val bucketList = minioClient.listBuckets()bucketList.forEach { bucket ->println("${bucket.name()} -- ${bucket.creationDate()}")}}
现在 MinIO 上有两个文件夹,如下:
运行结果如下:
删除文件夹
案例:删除文件夹 dir2
@Testfun test3() {minioClient.removeBucket(RemoveBucketArgs.builder().bucket("dir2").build())}
MinIO 中对 Object(文件) 的操作
两种文件上传的方式
案例:将本地 "D:/tmp/滑稽.gif" 图片上传到 MinIO 的 "dir1" 文件夹下,并重命名为 "test.gif"
a)stream 方式
@Testfun test1() {val file = File("D:/tmp/滑稽.gif")minioClient.putObject(PutObjectArgs.builder().bucket("dir1").`object`("test.gif")//stream://第二个参数(long objectSize): 要上传的文件大小//第三个参数(long partSize): 指定缓冲区的大小//这两个如果不知道,都可以使用 -1.stream(FileInputStream(file), file.length(), -1).build())}
b) upload 方式(更简单一些)
@Testfun test2() {minioClient.uploadObject(UploadObjectArgs.builder().bucket("dir1").`object`("test.gif").filename("D:/tmp/滑稽.gif").build())}
c)运行结果在 MinIO 上可以观察到:
相比较上面的上传文件的方式,以下这种上传文件的方式就更加简单
查看文件状态(是否存在)
案例:查询 "dir1" 文件夹下的 "test.gif" 文件的状态
@Testfun test3() {val result = minioClient.statObject(StatObjectArgs.builder().bucket("dir1").`object`("test.gif").build())println(result)}
a)如果文件存在,运行结果如下:
b)如果文件不存在,抛出异常如下:
c)对于文件不存在的情况,也可以做出如下处理
@Testfun test3() {try {val result = minioClient.statObject(StatObjectArgs.builder().bucket("dir1").`object`("testa1.gif").build())println(result)} catch (e: ErrorResponseException) {println("文件不存在!")println(e.message)}}
运行结果如下:
生成带签名的URL路径
案例:给 MinIO 上的 "dir1" 文件夹下的 "test.gif" 文件生成一个带签名的 url 路径(get 请求).
@Testfun test4() {val url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket("dir1").`object`("test.gif").method(Method.GET) //指定生成的 url 请求方式// .expiry(3, TimeUnit.SECONDS) 设置签名的过期时间.build())println(url)}
运行结果如下:
通过这个 url 就可以访问到图片
怎么使用不带签名的 url 直接访问
a)后台修改
下图位置,可以设置成 public 的,这样就可以通过不带签名的 url 直接访问到图片.
这样所有用户都能访问这个图片.
值得注意的是,如果设置成 public,会比较危险,因为这样意味着所有用户都能对这个桶下的文件进行 增删改查...
不过也可以给这个文件夹赋予只读权限(只有登录了 MinIO 的用户才能进行其他操作,比如你的程序最开始配置了 MinioClient,才可以进行其他操作):
再返回来,就可以看到该文件夹自动变成了自定义的权限:
打开就可以看到给你自动生成的 json 文件来实现针对 url 的只读权限控制:
b)创建桶的时候指定访问策略(只允许读操作)
Ps:代码中的 jsonConfig 就是从第一种方式中生成的 json 文件复制过来就可以,但是注意要修改以下文件名!
@Testfun test5() {//新建文件夹 dir2minioClient.makeBucket(MakeBucketArgs.builder().bucket("dir2").build())//设置文件夹的访问权限为 只读val jsonConfig = """
{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Principal": {"AWS": ["*"]},"Action": ["s3:GetBucketLocation"],"Resource": ["arn:aws:s3:::dir2"]},{"Effect": "Allow","Principal": {"AWS": ["*"]},"Action": ["s3:ListBucket"],"Resource": ["arn:aws:s3:::dir2"],"Condition": {"StringEquals": {"s3:prefix": ["*"]}}},{"Effect": "Allow","Principal": {"AWS": ["*"]},"Action": ["s3:GetObject"],"Resource": ["arn:aws:s3:::dir2/**"]}]
}""".trimIndent()minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket("dir2").config(jsonConfig).build())//上传图片minioClient.uploadObject(UploadObjectArgs.builder().bucket("dir2").`object`("test.gif").filename("D:/tmp/滑稽.gif").build())val url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket("dir2").`object`("test.gif").method(Method.GET).build()).split("?")[0] //这样就可以不需要 签名 部分了println(url)}
运行结果如下:
之后就可以直接不带 签名档 url 通过 url 来访问啦~
从 MinIO 上获取图片,然后下载到本地磁盘'
案例:获取 文件夹"dir1" 中的 "test.gif"文件 ,保存到本地磁盘的 "D:/tmp/" 路径下,并重命名为 "123.gif"
@Testfun test6() {val resp = minioClient.getObject(GetObjectArgs.builder().bucket("dir1").`object`("test.gif").build())val file = FileOutputStream("D:/tmp/123.gif")val result = resp.transferTo(file)println(result)}
运行结果如下:
获取文件夹下的所有文件
案例:获取 dir1 文件夹下的所有文件名
@Testfun test7() {val objects = minioClient.listObjects(ListObjectsArgs.builder().bucket("dir1").build())objects.forEach { result ->val item = result.get()println(item.objectName())}}
运行结果如下:
删除文件
案例:删除文件夹 "dir1" 中的 test2.jpg 文件.
@Testfun test8() {minioClient.removeObject(RemoveObjectArgs.builder().bucket("dir1").`object`("test2.jpg").build())}