SpringBoot-(三十五)快速使用Minio

本文最后更新于:May 13, 2023 pm

MinIO 是一个高性能的分布式对象存储系统。基于Apache License 开源协议,兼容Amazon S3云存储接口。适合存储非结构化数据,如图片,音频,视频,日志等。对象文件最大可以达到5TB。MinIO 是专门为对象而构建的,所以单层架构可以毫不妥协地实现所有必要的功能。 结果是一个同时具有高性能、可扩展性和轻量级的云原生对象服务器。

目录

官方文档

安装

官方安装教程

这里以Windows为例:

安装Server

1
2
3
4
PS> Invoke-WebRequest -Uri "https://dl.min.io/server/minio/release/windows-amd64/minio.exe" -OutFile "C:\minio.exe" # 下载,安装的地址为:C:\minio.exe 可自定义路径
PS> setx MINIO_ROOT_USER admin # 设置用户admin
PS> setx MINIO_ROOT_PASSWORD password # 设置密码password
PS> C:\minio.exe server F:\Data --console-address ":9001" # F:\Data表示数据存储地址,9001是控制台的端口,默认即可

安装Client

1
2
PS> Invoke-WebRequest -Uri "https://dl.minio.io/client/mc/release/windows-amd64/mc.exe" -OutFile "C:\mc.exe" # 下载,安装地址为:C:\mc.exe 可自定义路径
PS> C:\mc.exe alias set myminio/ http://MINIO-SERVER MYUSER MYPASSWORD # 启动
  • MINIO-SERVER:是在Server启动后,控制台上会显示一个地址。将Command-line中显示的一条命令复制过来即可。
  • MYUSER:即设置的用户名。
  • MYPASSWORD:设置的密码。

查看状态

1
systemctl status minio.service

SpringBoot使用

依赖

1
2
3
4
5
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.4.0</version>
</dependency>

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

spring:
servlet:
multipart:
max-file-size: 50MB
max-request-size: 50MB
minio:
#服务端地址
endpoint: http://192.168.0.101:9000
#账号
accessKey: admin
#密码
secretKey: adminminio
#地址
fileHost: http://192.168.0.101:9000

配置MinioClient

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.tothefor.demo.minio;

import io.minio.MinioClient;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
* @Author DragonOne
* @Date 2023/4/26 16:16
*/

@Data
@Configuration
public class MinIoClientConfig {

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

/**
* 注入minio 客户端
*
* @return
*/
@Bean
public MinioClient minioClient() {

return MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
}

}

工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.tothefor.demo.minio;

import io.minio.BucketExistsArgs;
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


/**
* @Author DragonOne
* @Date 2023/4/30 13:40
*/
@Component
public class CustomMinio {

@Autowired
private MinioClient minioClient;

}

测试Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.tothefor.demo;

import com.tothefor.demo.minio.CustomMinio;
import com.tothefor.demo.minio.MinioUtilS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
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 javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
* @Author DragonOne
* @Date 2023/4/27 17:47
*/

@RestController
@RequestMapping("/demo")
public class DemoCtr {

@Autowired
private CustomMinio customMinio;


}

功能

Bucket桶

判断Bucket桶是否存在

public boolean bucketExists(BucketExistsArgs args)

1
2
3
@Autowired
private MinioClient minioClient;
minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
  • bucketName:桶名称。
创建Bucket

public void makeBucket(MakeBucketArgs args)

1
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
删除空Bucket

public void removeBucket(RemoveBucketArgs args)

1
minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
  • 如果删除的Bucket中存在数据,则会删除失败。

上传资源

  • objectName:即存储在Minio中时需要显示的名称,需要带文件后缀!!!
流式上传

public ObjectWriteResponse putObject(PutObjectArgs args)

1
2
3
4
5
6
7
8
9
10
11
@Autowired
private MinioClient minioClient;

public void putObject(InputStream inputStream, String objectName, String contentType) throws Exception {
minioClient.putObject(PutObjectArgs.builder()
.bucket("test")
.object(objectName)
.stream(inputStream, inputStream.available(), -1)
.contentType(contentType)
.build());
}

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@PostMapping("/put")
public String put(MultipartFile file) throws Exception {
String name = file.getOriginalFilename(); // 文件名称和文件后缀
InputStream inputStream = file.getInputStream();
long l = System.currentTimeMillis();
String contentType = file.getContentType();
name = l + name;
try {
customMinio.putObject(inputStream, name, contentType);
} catch (Exception e) {
System.out.println("Err");
}
System.out.println("ok");
return "ok";
}
本地文件上传

public void uploadObject(UploadObjectArgs args)

1
2
3
4
5
6
7
8
public ObjectWriteResponse uploadFile(String bucketName, String objectName, String fileName) {
return minioClient.uploadObject(
UploadObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.filename(fileName)
.build());
}

测试

1
2
3
4
5
6
@PostMapping("/upload")
public String newUpload() {
ObjectWriteResponse test = customMinio.uploadFile("test", "test-upload.pdf", "D:\\Desktop\\微信小程序接口.pdf");
System.out.println("ok");
return "ok";
}

获取资源

获取资源流

public InputStream getObject(GetObjectArgs args)

1
2
3
4
5
6
public InputStream getObject(String objectName) throws Exception {
return minioClient.getObject(GetObjectArgs.builder()
.bucket("test")
.object(objectName)
.build());
}

测试:(下载)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@PostMapping("/get")
public String put(HttpServletResponse response) throws Exception {
InputStream object = customMinio.getObject2("test-upload.pdf");
BufferedInputStream bis = new BufferedInputStream(object);
ServletOutputStream os = response.getOutputStream();
// response.setContentType("application/pdf");
response.setContentType("application/force-download;charset=utf-8");// 设置强制下载而不是直接打开
response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(System.currentTimeMillis() + "", "UTF-8"));// 设置文件名
try {
byte[] buffer = new byte[1024 * 1024 * 1024]; //buffer 1M
int offset = bis.read(buffer);
while (offset != -1) {
os.write(buffer, 0, offset);
offset = bis.read(buffer);
}
os.flush();
}catch (Exception e){
e.printStackTrace();
}

return "ok";
}
获取访问链接

public String getPresignedObjectUrl(GetPresignedObjectUrlArgs args)

1
2
3
4
5
6
7
8
9
@PostMapping("/get")
public String put() throws Exception {
return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
.bucket("test")
.object("test-upload.pdf")
.method(Method.POST)
.build());

}

下载资源

1
2
3
4
5
6
7
8
9
@RequestMapping("/get")
public void put() throws Exception {
minioClient.downloadObject(DownloadObjectArgs.builder()
.bucket("test")
.object("test-upload.pdf")
.filename("test-down.pdf") // 下载的位置,默认项目根目录
.build());
System.out.println("ok");
}

删除资源

删除单个

public void removeObject(RemoveObjectArgs args)

1
2
3
4
5
6
7
8
@RequestMapping("/get")
public void put() throws Exception {
minioClient.removeObject(RemoveObjectArgs.builder()
.bucket("test")
.object("file1682838981970")
.build());
System.out.println("ok");
}
批量删除

public Iterable<Result<DeleteError>> removeObjects(RemoveObjectsArgs args)

1
2
3
4
5
6
7
8
9
10
11
12
@RequestMapping("/get")
public void put() throws Exception {
List<DeleteObject> objects = new LinkedList<>();
objects.add(new DeleteObject("1682839565915file"));
objects.add(new DeleteObject("file1682838817069"));
objects.add(new DeleteObject("file1682838858550"));
minioClient.removeObjects(RemoveObjectsArgs.builder()
.bucket("test")
.objects(objects)
.build());
System.out.println("ok");
}