认识MinIO
什么是MinIO?
MinIO 是一个高性能、开源、分布式的对象存储系统 ,兼容 Amazon S3 API。
它允许你像使用 AWS S3 一样使用本地服务器或私有云来存储图片、视频、文档等非结构化数据。官网:MinIO | S3 Compatible Storage for AI
为什么要用MinIO实现文件上传?
开源免费
相对于某些付费的云存储方案,Minio完全开源而且免费,功能强大,性能高,它能够处理高并发的文件上传和下载请求,适合需要处理大量数据的应用场景。MinIO 的分布式架构允许用户轻松扩展存储容量,满足不断增长的数据需求。而且如果你一直用本地内存存储你项目中的文件的话,过久了会不好处理,内容越来越少就问你慌不慌吧(除非你是富哥,那是其他的说法了)。
易于部署和管理
MinIO 的部署非常简单,可以在各种环境中运行,包括本地服务器、云平台和容器化环境。MinIO 还提供了丰富的管理工具和监控功能,帮助用户轻松管理和维护存储系统。
如何使用MinIO
首先,我们要下载MinIO
下载地址:https://www.minio.org.cn/download.shtml#/windows
进去之后按照箭头指示点击进行下载,下载好之后放在存放minio位置的bin文件夹下
找地方创建存放位置
在等待下载成功的这段时间我们先在你的电脑上显眼而且空着的文件夹下创建minio的妨位置(注意了嗷,千万不要中文路径,因为你的电脑有时候会识别不了中文的)
首先创建一个minio文件夹
然后在里minio文件夹里面创建三个文件夹,如下图:
bin:存放mc.exe 以及minio.exe 文件(也就是下载的那两个文件)
data:存放相关数据文件
logs:存储相关日志
启动minio
一般启动文件直接点击.exe文件就好了,但是MinIO却不是这样子的,你双击.exe文件不能启动,只能通过两种方式,第一种是通过命令行的方式,第二种就是通过写一个.bat文件,运行它即可启动minio
以下是两种命令的运行方式
第一种:命令行
以管理员权限打开cmd窗口,进入到minio.exe所在bin目录
1.设置用户名
用于登录minio客户端
setx MINIO_ROOT_USER name
控制台输入用于登录minio客户端的用户名(这里的name可以自己决定变一个,前提是必须大于3个字符,比如你想换 root 作为用户名,那就是setx MINIO_ROOT_USER root):
2.设置登录密码
setx MINIO_ROOT_PASSWORD password
控制台输入用于登录minio客户端的密码(这里的password可以自己决定变一个,前提是必须大于8个字符,比如你想换 12345678作为密码
3.启动Minio服务
.\minio.exe server F:\develop\minio\data --console-address "127.0.0.1:9000" --address "127.0.0.1:9001"
F:\develop\minio\data 注意,这里是我存放minio的路径,如果是你操作的时候改成自己的地址
9090是控制台端口,
9000是服务的端口
第二种:编写bat文件
编写bat文件可以点击之后直接启动,但是启动之后不要关掉该命令行,不然访问不到MinIO的客户端
先在bin文件夹下创建一个.txt文本文件输以下代码【命名尽量不要中文】
set MINIO_ROOT_USER=admin
set MINIO_ROOT_PASSWORD=admin123
.\minio.exe server F:\develop\minio\data --console-address "localhost:9000" --address "localhost:9001" > F:\develop\minio\logs\minio.log 2>&1
下面是bat文件中的每一行的解释
- @echo off:关闭命令回显,使得命令行输出更干净。
- set MINIO_ROOT_USER=minioadmin 和 set MINIO_ROOT_PASSWORD=minioadmin:设置环境变量,用于 MinIO 的用户名和密码。
- minio.exe server ...:启动 MinIO 服务器,指定数据目录、控制台地址、服务地址以及日志文件路径。
- 2>&1:将标准错误输出也重定向到日志文件。
如果你的9001端口要用到可以改成其他没用到的端口,
(千万别忘记保存)然后同时按下ctrl+s保存文件
保存之后把文件后缀改成.bat文件,弹出提示直接按下确定就可以了,没事的。
如果没看到文件后缀,可以在查看中选择详细信息,就会有了
更改完之后 双击启动出现这个cmd窗口,千万不要关闭!千万不要关闭!千万不要关闭!
使用MinIO客户端
进入MinIO
到浏览器中输入http://localhost:9000/ 就可以进入登录页面了,输入你的账号名和密码
就可以进来了,我的demo桶是我自己创建的,你们第一次进去的时候没有桶嗷。
创建新桶
桶的作用就是用来存储你上传的文件或者图片的
1.按照下图中的操作新建桶
2. 输入桶名,创建桶
创建好之后你就有一个桶啦
3.更改桶 访问策略(Access Policy)
还要一步要做的,点进去更改桶 访问策略(Access Policy)把Private改成Public
改好之后点击右下角的Set就可以了
使用MinIO客户端上传文件
点击上传之后选择文件上传,这样子就成功了
至此,使用MinIO客户端上传文件就完成了
在SpringBoot项目中使用MinIO文件上传
本篇重头戏来了,接下来将会演示如何在SpringBoot项目中使用MinIO实现文件上传
第一步:在你项目的pom.xml文件中导入相关依赖
<!-- minio依赖-->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.6</version>
</dependency>
第二步:在你的application.yml文件中配置相关信息
minio:
#MinIO访问路径,这里不一定要跟我,跟随你前面.bat文件配置的一样就好了
endpoint: http://localhost:9001
#用户名
access-key: admin
#密码
secret-key: admin123
#桶名,你刚才创建的桶名
bucket-name: demo
第三步:创建返回类
返回后端信息给前端
1.Result类
//如果想使用lombok注解,如果想使用在pom文件中导入相关依赖就可以了
@Data
public class Result {
private int code;//编码 200/400
private String msg;//成功/失败
private Long total;//总记录数
private Object data;//数据
public Result() {
}
public Result(int code, String msg, Long total, Object data) {
this.code = code;
this.msg = msg;
this.total = total;
this.data = data;
}
public static Result fail() {
return result(400, "失败", 0L, null);
}
public static Result fail(String msg) {
return result(400, msg, 0L, null);
}
public static Result success() {
return result(200, "成功", 0L, null);
}
public static Result success(String msg) {
return result(200, msg, 0L, null);
}
public static Result success(Object data) {
return result(200, "成功", 0L, data);
}
public static Result success(List<?> dataList) {
return result(200, "成功", (long) dataList.size(), dataList);
}
public static Result success(String msg, List<?> dataList) {
return result(200, msg, (long) dataList.size(), dataList);
}
public static Result success(Object data, Long total) {
return result(200, "成功", total, data);
}
private static Result result(int code, String msg, Long total, Object data) {
Result res = new Result();
res.setData(data);
res.setMsg(msg);
res.setCode(code);
res.setTotal(total);
return res;
}
}
2.返回文件信息的DTO类
@Data
public class FileInfoDTO {
private String fileName;//文件名
private String fileUrl;//文件路径
private long fileSize;//文件大小
}
第四步:定义 MinIOPojo读取yml文件中定义的连接信息
@Component
@ConfigurationProperties(prefix = "minio")
@Data
public class MinIoPojo {
/**
* minio连接信息
*/
private String endpoint;
private String accessKey;
private String secretKey;
private String bucketName;
}
第五步:定义MinIOConfig将MinioClient初始化
用来连接到客户端
/**
* 自定义bean,将MinioClient初始化
*/
@Data
@Configuration
public class MinioConfig {
@Autowired
private MinIoPojo minIoPojo;
@Bean
public MinioClient getMinioClient() {
return MinioClient.builder()
.endpoint(minIoPojo.getEndpoint())
.credentials(minIoPojo.getAccessKey(), minIoPojo.getSecretKey())
.build();
}
}
第六步:创建MinIOUtil 工具类
主要用来写文件上传或者以后的文件下载等逻辑,方便代码的复用
@Component
@Slf4j
public class MinIOUtil {
@Autowired
private MinioClient minioClient;
@Autowired
private MinIoPojo minIoPojo;
// 支持的文件类型集合
private final Set<String> allowedExtensions = new HashSet<>(Arrays.asList("jpg", "png", "gif", "pdf"));
// 默认最大大小(10MB)
private final long maxFileSize = 10 * 1024 * 1024;
//多文件上传
public Result uploads(MultipartFile[] files) {
if (files == null || files.length == 0){
return Result.fail("上传文件不能为空");
}
//本地时间
String format = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
//创建文件信息集合
List<FileInfoDTO> fileInfoList = new ArrayList<>();
try {
//判断桶是否存在
boolean bucketExists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(minIoPojo.getBucketName()).build());
if (!bucketExists) {
//创建桶
minioClient.makeBucket(MakeBucketArgs.builder().bucket(minIoPojo.getBucketName()).build());
}
//遍历文件
for (MultipartFile file : files) {
//跳过空文件
if (file.isEmpty()) {
continue;
}
//原文件名
String originalFilename = file.getOriginalFilename();
//获取文件名后缀
String suffixName = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
//判断文件类型是否允许上传
if (!allowedExtensions.contains(suffixName)) {
return Result.fail(suffixName+"类型不允许上传");
}
//判断文件大小是否允许上传
if (file.getSize() > maxFileSize) {
return Result.fail(originalFilename+"文件过大,不允许上传");
}
//避免文件名重复,生成新的文件名
String fileName = format + "/" + UUID.randomUUID() + "." + suffixName;
// 构建访问 URL
String fileUrl = minIoPojo.getEndpoint() + "/" + minIoPojo.getBucketName() + "/" + fileName;
// 上传文件到 MinIO 服务器
minioClient.putObject(PutObjectArgs.builder()
.bucket(minIoPojo.getBucketName())
.object(fileName)
.stream(file.getInputStream(), file.getSize(), -1)
.contentType(file.getContentType())
.build());
log.info("文件上传成功,文件名:{}", fileName);
FileInfoDTO dto = new FileInfoDTO();
dto.setFileName(originalFilename);
dto.setFileUrl(fileUrl);
dto.setFileSize(file.getSize());
fileInfoList.add(dto);
}
}catch (Exception e) {
e.printStackTrace();
return Result.fail("文件上传失败");
}
log.info("文件上传成功,文件信息:{}", fileInfoList);
if (fileInfoList.isEmpty()){
return Result.fail("文件列表为空,上传失败");
}
return Result.success(fileInfoList);
}
}
第七步:创建上传接口
@RestController
@RequestMapping("/minio")
public class MinIOController {
@Autowired
private MinIOUtil minIOUtil;
@PostMapping("/uploads")
public Result uploads(MultipartFile[] files) {
return minIOUtil.uploads(files);
}
}
至此,你已经在SpringBoot项目中写好了一整套用MinIO实现文件上传的逻辑和其使用接口
接口测试(Apifox)
现在让我们来测试一下,我这里用的是Apifox,用PostMan也可以的,设置如下
当我们上传一个文件时候返回的样子
同时上传多个文件是这样子的
这样子返回给前端的的数据就比较规范的(这样子他就没机会找你麻烦了)
当然,你也可以输入你图片的路劲到浏览器中查看上传的图片
然后我们再到MinIO的客户端中查看我们上传的图片
都上传成功了!!!