【8.3.4】【file】更新新版MinIO客户端的操作

master
stylefeng 2025-04-30 22:29:15 +08:00
parent 9fc535b87b
commit 86da86232b
4 changed files with 262 additions and 70 deletions

View File

@ -33,10 +33,6 @@
</dependency>
<!--minio客户端-->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>

View File

@ -36,14 +36,14 @@ import cn.stylefeng.roses.kernel.file.api.exception.FileException;
import cn.stylefeng.roses.kernel.file.api.exception.enums.FileExceptionEnum;
import cn.stylefeng.roses.kernel.file.api.expander.FileConfigExpander;
import cn.stylefeng.roses.kernel.file.api.pojo.props.MinIoProperties;
import cn.stylefeng.roses.kernel.file.minio.factory.MinIoConfigFactory;
import cn.stylefeng.roses.kernel.rule.util.HttpServletUtil;
import io.minio.MinioClient;
import io.minio.errors.InvalidEndpointException;
import io.minio.errors.InvalidPortException;
import io.minio.policy.PolicyType;
import io.minio.*;
import lombok.extern.slf4j.Slf4j;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.rmi.NoSuchObjectException;
import java.util.HashMap;
import java.util.Map;
@ -53,6 +53,7 @@ import java.util.Map;
* @author fengshuonan
* @since 2020/10/31 10:35
*/
@Slf4j
public class MinIoFileOperator implements FileOperatorApi {
private final Object LOCK = new Object();
@ -84,12 +85,7 @@ public class MinIoFileOperator implements FileOperatorApi {
String secretKey = minIoProperties.getSecretKey();
// 创建minioClient实例
try {
minioClient = new MinioClient(endpoint, accessKey, secretKey);
} catch (InvalidEndpointException | InvalidPortException e) {
// 组装提示信息
throw new FileException(FileExceptionEnum.MINIO_FILE_ERROR, e.getMessage());
}
minioClient = MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
}
@Override
@ -105,52 +101,85 @@ public class MinIoFileOperator implements FileOperatorApi {
@Override
public boolean doesBucketExist(String bucketName) {
try {
return minioClient.bucketExists(bucketName);
return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
} catch (Exception e) {
// 组装提示信息
throw new FileException(FileExceptionEnum.MINIO_FILE_ERROR, e.getMessage());
log.error("MinIo校验桶是否存在时异常", e);
return false;
}
}
@Override
public void setBucketAcl(String bucketName, BucketAuthEnum bucketAuthEnum) {
setFileAcl(bucketName, "*", bucketAuthEnum);
try {
// 创建规则的json
String policyJson = MinIoConfigFactory.createPolicyJson(bucketAuthEnum, bucketName);
// 使用 SetBucketPolicyArgs 设置策略
SetBucketPolicyArgs args = SetBucketPolicyArgs.builder()
.bucket(bucketName)
.config(policyJson)
.build();
minioClient.setBucketPolicy(args);
} catch (Exception e) {
log.error("Error occurred while setting bucket ACL: ", e);
throw new FileException(FileExceptionEnum.MINIO_FILE_ERROR, e.getMessage());
}
}
@Override
public boolean isExistingFile(String bucketName, String key) {
InputStream inputStream = null;
try {
inputStream = minioClient.getObject(bucketName, key);
if (inputStream != null) {
return true;
}
} catch (Exception e) {
// 使用 StatObjectArgs 构建查询参数
StatObjectResponse response = minioClient.statObject(
StatObjectArgs.builder()
.bucket(bucketName)
.object(key)
.build()
);
// 如果文件存在statObject 不会抛出异常,返回 true
return true;
} catch (NoSuchObjectException e) {
// 如果文件不存在,会抛出 NoSuchObjectException返回 false
return false;
} catch (Exception e) {
log.error("MINIO无法找到文件 ", e);
return false;
} finally {
IoUtil.close(inputStream);
}
return false;
}
@Override
public void storageFile(String bucketName, String key, byte[] bytes) {
if (bytes != null && bytes.length > 0) {
// 字节数组转字节数组输入流
if (bytes == null || bytes.length == 0) {
return;
}
try {
// 检查存储桶是否存在,不存在直接返回
boolean isBucketExist = this.doesBucketExist(bucketName);
if (!isBucketExist) {
log.error("无法存储文件到桶,桶不存在!桶名称:{}", bucketName);
return;
}
// 将字节数组转换为输入流
ByteArrayInputStream byteArrayInputStream = IoUtil.toStream(bytes);
// 获取文件类型
ByteArrayInputStream tmp = IoUtil.toStream(bytes);
String type = FileTypeUtil.getType(tmp);
String type = FileTypeUtil.getType(byteArrayInputStream);
String fileContentType = getFileContentType(String.format("%s%s", ".", type));
try {
minioClient.putObject(bucketName, key, byteArrayInputStream, bytes.length, fileContentType);
} catch (Exception e) {
// 组装提示信息
throw new FileException(FileExceptionEnum.MINIO_FILE_ERROR, e.getMessage());
}
// 上传文件
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(key)
// -1 表示不限制流的大小
.stream(byteArrayInputStream, bytes.length, -1)
.contentType(fileContentType)
.build()
);
} catch (Exception e) {
log.error("MINIO文件操作异常", e);
throw new FileException(FileExceptionEnum.MINIO_FILE_ERROR, e.getMessage());
}
}
@ -165,10 +194,10 @@ public class MinIoFileOperator implements FileOperatorApi {
@Override
public byte[] getFileBytes(String bucketName, String key) {
try {
InputStream inputStream = minioClient.getObject(bucketName, key);
InputStream inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(key).build());
return IoUtil.readBytes(inputStream);
} catch (Exception e) {
// 组装提示信息
log.error("MINIO文件操作异常", e);
throw new FileException(FileExceptionEnum.MINIO_FILE_ERROR, e.getMessage());
}
}
@ -176,18 +205,15 @@ public class MinIoFileOperator implements FileOperatorApi {
@Override
public void setFileAcl(String bucketName, String key, BucketAuthEnum bucketAuthEnum) {
try {
if (bucketAuthEnum.equals(BucketAuthEnum.PRIVATE)) {
minioClient.setBucketPolicy(bucketName, key, PolicyType.NONE);
} else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ)) {
minioClient.setBucketPolicy(bucketName, key, PolicyType.READ_ONLY);
} else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ_WRITE)) {
minioClient.setBucketPolicy(bucketName, key, PolicyType.READ_WRITE);
} else if (bucketAuthEnum.equals(BucketAuthEnum.MINIO_WRITE_ONLY)) {
minioClient.setBucketPolicy(bucketName, key, PolicyType.WRITE_ONLY);
}
// 根据枚举值设置对应的策略
String policyJson = MinIoConfigFactory.createKeyPolicyJson(bucketName, key, bucketAuthEnum);
SetBucketPolicyArgs args = SetBucketPolicyArgs.builder()
.bucket(bucketName)
.config(policyJson)
.build();
minioClient.setBucketPolicy(args);
} catch (Exception e) {
// 组装提示信息
log.error("MINIO文件操作异常", e);
throw new FileException(FileExceptionEnum.MINIO_FILE_ERROR, e.getMessage());
}
}
@ -195,9 +221,23 @@ public class MinIoFileOperator implements FileOperatorApi {
@Override
public void copyFile(String originBucketName, String originFileKey, String newBucketName, String newFileKey) {
try {
minioClient.copyObject(originBucketName, originFileKey, newBucketName, newFileKey);
// 构建源文件的 CopySource 对象
CopySource copySource = CopySource.builder()
.bucket(originBucketName)
.object(originFileKey)
.build();
// 构建拷贝文件的目标参数
CopyObjectArgs copyObjectArgs = CopyObjectArgs.builder()
.source(copySource)
.bucket(newBucketName)
.object(newFileKey)
.build();
// 执行拷贝操作
minioClient.copyObject(copyObjectArgs);
} catch (Exception e) {
// 组装提示信息
log.error("MINIO文件操作异常", e);
throw new FileException(FileExceptionEnum.MINIO_FILE_ERROR, e.getMessage());
}
}
@ -211,8 +251,12 @@ public class MinIoFileOperator implements FileOperatorApi {
// 获取context-path
String contextPath = HttpServletUtil.getRequest().getContextPath();
return FileConfigExpander.getServerDeployHost() + contextPath + FileConstants.FILE_PREVIEW_BY_OBJECT_NAME + "?fileBucket=" + bucketName + "&fileObjectName=" + key + "&token=" + token;
return FileConfigExpander.getServerDeployHost()
+ contextPath
+ FileConstants.FILE_PREVIEW_BY_OBJECT_NAME
+ "?fileBucket=" + bucketName
+ "&fileObjectName=" + key
+ "&token=" + token;
}
@Override
@ -220,18 +264,21 @@ public class MinIoFileOperator implements FileOperatorApi {
// 获取context-path
String contextPath = HttpServletUtil.getRequest().getContextPath();
return FileConfigExpander.getServerDeployHost() + contextPath + FileConstants.FILE_PREVIEW_BY_OBJECT_NAME + "?fileBucket=" + bucketName + "&fileObjectName=" + key;
return FileConfigExpander.getServerDeployHost()
+ contextPath
+ FileConstants.FILE_PREVIEW_BY_OBJECT_NAME
+ "?fileBucket=" + bucketName
+ "&fileObjectName=" + key;
}
@Override
public void deleteFile(String bucketName, String key) {
try {
minioClient.removeObject(bucketName, key);
minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(key).build());
} catch (Exception e) {
// 组装提示信息
log.error("MINIO文件操作异常", e);
throw new FileException(FileExceptionEnum.MINIO_FILE_ERROR, e.getMessage());
}
}
@Override
@ -247,7 +294,7 @@ public class MinIoFileOperator implements FileOperatorApi {
*/
private Map<String, String> getFileContentType() {
synchronized (LOCK) {
if (contentType.size() == 0) {
if (contentType.isEmpty()) {
contentType.put(".bmp", "application/x-bmp");
contentType.put(".gif", "image/gif");
contentType.put(".fax", "image/fax");

View File

@ -0,0 +1,157 @@
package cn.stylefeng.roses.kernel.file.minio.factory;
import cn.stylefeng.roses.kernel.file.api.enums.BucketAuthEnum;
/**
* MinIO
*
* @author fengshuonan
* @since 2025/4/30 21:56
*/
public class MinIoConfigFactory {
/**
* JSON
*
* @author fengshuonan
* @since 2025/4/30 21:53
*/
public static String createPolicyJson(BucketAuthEnum bucketAuthEnum, String bucketName) {
switch (bucketAuthEnum) {
case PRIVATE:
return "{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Effect\": \"Deny\",\n" +
" \"Principal\": \"*\",\n" +
" \"Action\": \"s3:*\",\n" +
" \"Resource\": \"arn:aws:s3:::" + bucketName + "/*\"\n" +
" }\n" +
" ]\n" +
"}";
case PUBLIC_READ:
return "{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Effect\": \"Allow\",\n" +
" \"Principal\": \"*\",\n" +
" \"Action\": \"s3:GetObject\",\n" +
" \"Resource\": \"arn:aws:s3:::" + bucketName + "/*\"\n" +
" }\n" +
" ]\n" +
"}";
case PUBLIC_READ_WRITE:
return "{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Effect\": \"Allow\",\n" +
" \"Principal\": \"*\",\n" +
" \"Action\": [\n" +
" \"s3:GetObject\",\n" +
" \"s3:PutObject\"\n" +
" ],\n" +
" \"Resource\": \"arn:aws:s3:::" + bucketName + "/*\"\n" +
" }\n" +
" ]\n" +
"}";
case MINIO_WRITE_ONLY:
return "{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Effect\": \"Allow\",\n" +
" \"Principal\": \"*\",\n" +
" \"Action\": \"s3:PutObject\",\n" +
" \"Resource\": \"arn:aws:s3:::" + bucketName + "/*\"\n" +
" },\n" +
" {\n" +
" \"Effect\": \"Deny\",\n" +
" \"Principal\": \"*\",\n" +
" \"Action\": \"s3:GetObject\",\n" +
" \"Resource\": \"arn:aws:s3:::" + bucketName + "/*\"\n" +
" }\n" +
" ]\n" +
"}";
default:
throw new IllegalArgumentException("Unsupported bucket auth enum: " + bucketAuthEnum);
}
}
/**
* JSON
*
* @author fengshuonan
* @since 2025/4/30 22:15
*/
public static String createKeyPolicyJson(String bucketName, String key, BucketAuthEnum bucketAuthEnum) {
switch (bucketAuthEnum) {
case PRIVATE:
return String.format(
"{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Effect\": \"Deny\",\n" +
" \"Principal\": \"*\",\n" +
" \"Action\": \"s3:*\",\n" +
" \"Resource\": \"arn:aws:s3:::%s/%s\"\n" +
" }\n" +
" ]\n" +
"}", bucketName, key);
case PUBLIC_READ:
return String.format(
"{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Effect\": \"Allow\",\n" +
" \"Principal\": \"*\",\n" +
" \"Action\": \"s3:GetObject\",\n" +
" \"Resource\": \"arn:aws:s3:::%s/%s\"\n" +
" }\n" +
" ]\n" +
"}", bucketName, key);
case PUBLIC_READ_WRITE:
return String.format(
"{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Effect\": \"Allow\",\n" +
" \"Principal\": \"*\",\n" +
" \"Action\": [\n" +
" \"s3:GetObject\",\n" +
" \"s3:PutObject\"\n" +
" ],\n" +
" \"Resource\": \"arn:aws:s3:::%s/%s\"\n" +
" }\n" +
" ]\n" +
"}", bucketName, key);
case MINIO_WRITE_ONLY:
return String.format(
"{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Effect\": \"Allow\",\n" +
" \"Principal\": \"*\",\n" +
" \"Action\": \"s3:PutObject\",\n" +
" \"Resource\": \"arn:aws:s3:::%s/%s\"\n" +
" },\n" +
" {\n" +
" \"Effect\": \"Deny\",\n" +
" \"Principal\": \"*\",\n" +
" \"Action\": \"s3:GetObject\",\n" +
" \"Resource\": \"arn:aws:s3:::%s/%s\"\n" +
" }\n" +
" ]\n" +
"}", bucketName, key);
default:
throw new IllegalArgumentException("Unsupported bucket auth enum: " + bucketAuthEnum);
}
}
}

10
pom.xml
View File

@ -129,8 +129,7 @@
<qingyun.oss.version>2.5.1</qingyun.oss.version>
<qcloud.sms>3.1.57</qcloud.sms>
<elasticsearch.version>7.9.2</elasticsearch.version>
<aws.sdk.version>1.11.106</aws.sdk.version>
<minio.version>3.0.10</minio.version>
<minio.version>8.5.17</minio.version>
<rocketmq.version>4.5.2</rocketmq.version>
<easy.captcha>1.6.2</easy.captcha>
<guns.groovy.version>3.0.22</guns.groovy.version>
@ -253,13 +252,6 @@
</dependency>
<!--MinIo客户端sdk-->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-bom</artifactId>
<version>${aws.sdk.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>