官方文档
下载安装
下载地址:🔗
Windows
https://dl.min.io/server/minio/release/windows-amd64/minio.exe
Linux
wget http://dl.minio.org.cn/server/minio/release/linux-amd64/minio
MacOS
brewinstall minio/stable/minio
运行
Windows
D:\MinIO>minio.exe server ./data
Linux(后台启动)
chmod +x miniocd /home/minio
./minio server --console-address"0.0.0.0:9100" /home/minio/data> /home/minio/minio.log2>&1&
MacOS
minio server /data
修改用户名密码
export MINIO_ROOT_USER= rootexport MINIO_ROOT_PASSWORD=88888888
创建存储桶
修改访问权限
- 进入存储桶(Buckets)
- 点击
Manage
- 修改
Access Policy
为public
Spring Boot 整合 MinIO
添加Maven依赖
<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.3.6</version></dependency>
解决依赖冲突
使用minio8.3.6
版本的依赖,报下列异常:
An attempt was made to call a method that does not exist. The attempt was made from the following location:
io.minio.S3Base.<clinit>(S3Base.java:105)
The following method did not exist:
okhttp3.RequestBody.create([BLokhttp3/MediaType;)Lokhttp3/RequestBody;
The method's class, okhttp3.RequestBody, is available from the following locations:
jar:file:/D:/repository/com/squareup/okhttp3/okhttp/3.14.9/okhttp-3.14.9.jar!/okhttp3/RequestBody.class
The class hierarchy was loaded from the following locations:
okhttp3.RequestBody: file:/D:/repository/com/squareup/okhttp3/okhttp/3.14.9/okhttp-3.14.9.jar
Action:
Correct the classpath of your application so that it contains a single, compatible version of okhttp3.RequestBody
注意:由于okhttp3
依赖冲突,默认的版本低于minio
所需版本,会导致启动失败,可通过以下方法解决:
- 降低
MinIO
版本
<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.2.1</version></dependency>
- 引入高版本的
okhttp
依赖
<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.9.3</version></dependency>
配置application.yml
文件
# MinIO配置minio:# 服务地址endpoint: http://127.0.0.1:9000# 文件地址fileHost: http://127.0.0.1:9000# 存储桶名称bucket: starimmortal# 用户名access-key: minioadmin# 密码secret-key: minioadmin
工具类
importio.minio.*;importio.minio.http.Method;importio.minio.messages.Bucket;importio.minio.messages.Item;importlombok.extern.slf4j.Slf4j;importorg.springframework.stereotype.Component;importorg.springframework.web.multipart.MultipartFile;importjava.io.ByteArrayInputStream;importjava.io.InputStream;importjava.io.UnsupportedEncodingException;importjava.net.URLDecoder;importjava.util.ArrayList;importjava.util.List;importjava.util.Optional;/**
* MinIO工具类
*
* @author william@StarImmortal
* @date 2022/04/19
*/@Component@Slf4jpublicclassMinioUtil{/**
* MinioClient实例
*/privatestaticMinioClient minioClient;/**
* Bucket所在地域对应的Endpoint
*/privatestaticString endpoint;/**
* 存储桶名称
*/privatestaticString bucketName;/**
* 用户名
*/privatestaticString accessKey;/**
* 密码
*/privatestaticString secretKey;/**
* 分隔符
*/privatestaticfinalString SEPARATOR="/";publicMinioUtil(){}publicMinioUtil(String endpoint,String bucketName,String accessKey,String secretKey){MinioUtil.endpoint= endpoint;MinioUtil.bucketName= bucketName;MinioUtil.accessKey= accessKey;MinioUtil.secretKey= secretKey;this.initMinioClient();}/**
* 创建基于Java端的MinioClient
*/publicvoidinitMinioClient(){try{if(null== minioClient){
log.info("开始创建MinioClient...");
minioClient=MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();createBucket(bucketName);
log.info("MinioClient创建完毕...");}}catch(Exception e){
log.error("MinIO服务器异常:{0}", e);}}/**
* 获取上传文件前缀路径
*
* @return 前缀路径
*/publicstaticStringgetBasisUrl(){return endpoint+ SEPARATOR+ bucketName+ SEPARATOR;}/****************************** Operate Bucket Start ******************************//**
* 启动SpringBoot容器的时候初始化Bucket,如果没有Bucket则创建
*/privatestaticvoidcreateBucket(String bucketName)throwsException{if(!bucketExists(bucketName)){
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());}}/**
* 判断Bucket是否存在
*
* @return true:存在,false:不存在
*/publicstaticbooleanbucketExists(String bucketName)throwsException{return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());}/**
* 获得Bucket策略
*
* @param bucketName 存储桶名称
* @return Bucket策略
*/publicstaticStringgetBucketPolicy(String bucketName)throwsException{return minioClient.getBucketPolicy(GetBucketPolicyArgs.builder().bucket(bucketName).build());}/**
* 获得所有Bucket列表
*
* @return Bucket列表
*/publicstaticList<Bucket>getAllBuckets()throwsException{return minioClient.listBuckets();}/**
* 根据存储桶名称获取其相关信息
*
* @param bucketName 存储桶名称
* @return 相关信息
*/publicstaticOptional<Bucket>getBucket(String bucketName)throwsException{returngetAllBuckets().stream().filter(b-> b.name().equals(bucketName)).findFirst();}/**
* 根据存储桶名称删除Bucket,true:删除成功;false:删除失败,文件或已不存在
*
* @param bucketName 存储桶名称
*/publicstaticvoidremoveBucket(String bucketName)throwsException{
minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());}/****************************** Operate Bucket End ******************************//****************************** Operate Files Start ******************************//**
* 判断文件是否存在
*
* @param bucketName 存储桶名称
* @param objectName 文件名
* @return true:存在;false:不存在
*/publicstaticbooleanisObjectExist(String bucketName,String objectName){boolean exist=true;try{
minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());}catch(Exception e){
exist=false;}return exist;}/**
* 判断文件夹是否存在
*
* @param bucketName 存储桶名称
* @param objectName 文件夹名称
* @return true:存在;false:不存在
*/publicstaticbooleanisFolderExist(String bucketName,String objectName){boolean exist=false;try{Iterable<Result<Item>> results= minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());for(Result<Item> result: results){Item item= result.get();if(item.isDir()&& objectName.equals(item.objectName())){
exist=true;}}}catch(Exception e){
exist=false;}return exist;}/**
* 根据文件前缀查询文件
*
* @param bucketName 存储桶名称
* @param prefix 前缀
* @param recursive 是否使用递归查询
* @return MinioItem列表
*/publicstaticList<Item>getAllObjectsByPrefix(String bucketName,String prefix,boolean recursive)throwsException{List<Item> list=newArrayList<>();Iterable<Result<Item>> objectsIterator= minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());if(objectsIterator!=null){for(Result<Item> o: objectsIterator){Item item= o.get();
list.add(item);}}return list;}/**
* 获取文件流
*
* @param bucketName 存储桶名称
* @param objectName 文件名
* @return 二进制流
*/publicstaticInputStreamgetObject(String bucketName,String objectName)throwsException{return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());}/**
* 断点下载
*
* @param bucketName 存储桶名称
* @param objectName 文件名称
* @param offset 起始字节的位置
* @param length 要读取的长度
* @return 二进制流
*/publicInputStreamgetObject(String bucketName,String objectName,long offset,long length)throwsException{return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).offset(offset).length(length).build());}/**
* 获取路径下文件列表
*
* @param bucketName 存储桶名称
* @param prefix 文件名称
* @param recursive 是否递归查找,false:模拟文件夹结构查找
* @return 二进制流
*/publicstaticIterable<Result<Item>>listObjects(String bucketName,String prefix,boolean recursive){return minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());}/**
* 使用MultipartFile进行文件上传
*
* @param bucketName 存储桶名称
* @param file 文件名
* @param objectName 对象名
* @param contentType 类型
* @return ObjectWriteResponse对象
*/publicstaticObjectWriteResponseuploadFile(String bucketName,MultipartFile file,String objectName,String contentType)throwsException{InputStream inputStream= file.getInputStream();return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).contentType(contentType).stream(inputStream, inputStream.available(),-1).build());}/**
* 上传本地文件
*
* @param bucketName 存储桶名称
* @param objectName 对象名称
* @param fileName 本地文件路径
*/publicstaticObjectWriteResponseuploadFile(String bucketName,String objectName,String fileName)throwsException{return minioClient.uploadObject(UploadObjectArgs.builder().bucket(bucketName).object(objectName).filename(fileName).build());}/**
* 通过流上传文件
*
* @param bucketName 存储桶名称
* @param objectName 文件对象
* @param inputStream 文件流
*/publicstaticObjectWriteResponseuploadFile(String bucketName,String objectName,InputStream inputStream)throwsException{return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(inputStream, inputStream.available(),-1).build());}/**
* 创建文件夹或目录
*
* @param bucketName 存储桶名称
* @param objectName 目录路径
*/publicstaticObjectWriteResponsecreateDir(String bucketName,String objectName)throwsException{return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(newByteArrayInputStream(newbyte[]{}),0,-1).build());}/**
* 获取文件信息, 如果抛出异常则说明文件不存在
*
* @param bucketName 存储桶名称
* @param objectName 文件名称
*/publicstaticStringgetFileStatusInfo(String bucketName,String objectName)throwsException{return minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build()).toString();}/**
* 拷贝文件
*
* @param bucketName 存储桶名称
* @param objectName 文件名
* @param srcBucketName 目标存储桶
* @param srcObjectName 目标文件名
*/publicstaticObjectWriteResponsecopyFile(String bucketName,String objectName,String srcBucketName,String srcObjectName)throwsException{return minioClient.copyObject(CopyObjectArgs.builder().source(CopySource.builder().bucket(bucketName).object(objectName).build()).bucket(srcBucketName).object(srcObjectName).build());}/**
* 删除文件
*
* @param bucketName 存储桶名称
* @param objectName 文件名称
*/publicstaticvoidremoveFile(String bucketName