文件管理客户端
package kl.gayxzc.csr.cilent;
import io.minio.GetObjectArgs;
import io.minio.GetObjectResponse;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.ListObjectsArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.Result;
import io.minio.StatObjectArgs;
import io.minio.http.Method;
import io.minio.messages.Item;
import kl.gayxzc.csr.constant.CsrErrorCode;
import kl.gayxzc.csr.constant.MinioConstant;
import kl.gayxzc.csr.exception.MinioException;
import kl.gayxzc.csr.utils.DateUtils;
import kl.gayxzc.csr.utils.UUIDUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@Slf4j
@Component("fileClient")
public class FileClient {
private MinioClient minioClient;
private BucketClient bucketClient;
@Value("${csr.minio.file-server-type}")
private String minioServerType;
@Autowired
public void setMinioClient(MinioClient minioClient) {
this.minioClient = minioClient;
}
@Autowired
public void setBucketClient(BucketClient bucketClient) {
this.bucketClient = bucketClient;
}
public List<String> put(MultipartFile... files) {
return put(null, files);
}
public List<String> put(String path, MultipartFile... files) {
if (files == null || files.length == 0) {
return new ArrayList<>();
}
List<String> list = new LinkedList<>();
for (MultipartFile file : files) {
list.add(put(path, file));
}
return list;
}
public void download(String fileName, HttpServletResponse response) {
GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(bucketClient.getDefaultBucket())
.object(fileName).build();
try (GetObjectResponse getObjectRes = minioClient.getObject(objectArgs)) {
byte[] buf = new byte[1024];
int len;
try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()) {
while ((len = getObjectRes.read(buf)) != -1) {
os.write(buf, 0, len);
}
os.flush();
byte[] bytes = os.toByteArray();
response.setCharacterEncoding("utf-8");
final String[] split = fileName.split(MinioConstant.DEFAULT_FILENAME_SEPARATOR);
String orgFilename = split.length > 1 ? split[split.length - 1] : fileName;
log.info("file original name is {}", orgFilename);
response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(orgFilename, "utf-8"));
try (ServletOutputStream stream = response.getOutputStream()) {
stream.write(bytes);
stream.flush();
}
}
} catch (Exception e) {
log.error("file {} download fail", fileName, e);
throw new MinioException(CsrErrorCode.DOWNLOAD_ERROR);
}
}
public void download(String fileName, String name, HttpServletResponse response) {
GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(name)
.object(fileName).build();
try (GetObjectResponse getObjectRes = minioClient.getObject(objectArgs)) {
byte[] buf = new byte[1024];
int len;
try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()) {
while ((len = getObjectRes.read(buf)) != -1) {
os.write(buf, 0, len);
}
os.flush();
byte[] bytes = os.toByteArray();
response.setCharacterEncoding("utf-8");
final String[] split = fileName.split(MinioConstant.DEFAULT_FILENAME_SEPARATOR);
String orgFilename = split.length > 1 ? split[split.length - 1] : fileName;
log.info("file original name is {}", orgFilename);
response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(orgFilename, "utf-8"));
try (ServletOutputStream stream = response.getOutputStream()) {
stream.write(bytes);
}
}
} catch (Exception e) {
log.error("file {} download fail", fileName, e);
throw new MinioException(CsrErrorCode.DOWNLOAD_ERROR);
}
}
public String preview(String fileName) {
final GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs.builder()
.bucket(bucketClient.getDefaultBucket())
.object(fileName)
.method(Method.GET)
.build();
try {
return minioClient.getPresignedObjectUrl(build);
} catch (Exception e) {
log.error("file {} preview failed", fileName, e);
throw new MinioException(CsrErrorCode.PREVIEW_ERROR);
}
}
public String preview(String fileName, String bucketName) {
final GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs.builder()
.bucket((Strings.isBlank(bucketName)) ? bucketClient.getDefaultBucket() : bucketName)
.object(fileName)
.method(Method.GET)
.build();
try {
return minioClient.getPresignedObjectUrl(build);
} catch (Exception e) {
log.error("file {} preview failed", fileName, e);
throw new MinioException(CsrErrorCode.PREVIEW_ERROR);
}
}
public void removeObject(String objectName) {
removeObject(bucketClient.getDefaultBucket(), objectName);
}
public void removeObject(String bucketName, String objectName) {
try {
minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
} catch (Exception e) {
log.error("file {} remove failed", objectName, e);
throw new MinioException(CsrErrorCode.REMOVE_ERROR);
}
}
public void deleteObject(String bucketName) {
boolean flag = bucketClient.bucketExists(bucketName);
if (flag) {
try {
log.info("递归列举{}下的所有文件循环删除", bucketName);
Iterable<Result<Item>> iterable = minioClient.listObjects(ListObjectsArgs.builder()
.bucket(bucketName)
.recursive(true)
.build());
for (Result<Item> itemResult : iterable) {
removeObject(bucketName, itemResult.get().objectName());
}
} catch (Exception e) {
log.error("递归列举{}下的所有文件循环删除异常", bucketName, e);
}
}
}
public String put(MultipartFile file) {
return put(null, file);
}
public String put(String path, MultipartFile file) {
beforePutCheck(file);
String originalFilename = file.getOriginalFilename();
assert originalFilename != null;
String objectName = buildObjectName(originalFilename, path);
try {
minioClient.putObject(buildPutObjectArgs(objectName, file));
return objectName;
} catch (Exception e) {
log.error("file[{}] upload failed", originalFilename, e);
throw new MinioException(CsrErrorCode.FILE_UPLOAD_FAILED_ERROR);
}
}
public String put(String path, MultipartFile file, String bucketName) {
beforePutCheck(file);
String originalFilename = file.getOriginalFilename();
assert originalFilename != null;
try {
minioClient.putObject(buildPutObjectArgs(path, file, bucketName));
return path;
} catch (Exception e) {
log.error("file[{}] upload failed", originalFilename, e);
throw new MinioException(CsrErrorCode.FILE_UPLOAD_FAILED_ERROR);
}
}
void beforePutCheck(MultipartFile file) {
String originalFilename = file.getOriginalFilename();
if (!StringUtils.hasText(originalFilename)) {
log.error("file {} cannot have an empty name", originalFilename);
throw new MinioException(CsrErrorCode.FILE_NAME_NO_NULL_ERROR);
}
}
String getFileSeparator() {
if (minioServerType.equals("WIN")) {
return MinioConstant.FILE_SEPARATOR_WIN;
} else if (minioServerType.equals("UNIX")) {
return MinioConstant.FILE_SEPARATOR_UNIX;
}
return File.separator;
}
String buildObjectName(String originalFilename, String path) {
String filename = UUIDUtils.uuid() + MinioConstant.DEFAULT_FILENAME_SEPARATOR + originalFilename;
String objectName = DateUtils.getNowDateStr(DateUtils.PATTERN_YYYYMMDD) + getFileSeparator() + filename;
if (path != null) {
objectName = path + "/" + filename;
}
return objectName;
}
PutObjectArgs buildPutObjectArgs(String objectName, MultipartFile file) throws Exception {
return PutObjectArgs.builder()
.bucket(bucketClient.getDefaultBucket())
.object(objectName)
.stream(file.getInputStream(), file.getSize(), -1)
.contentType(file.getContentType())
.build();
}
PutObjectArgs buildPutObjectArgs(String objectName, MultipartFile file, String bucketName) throws Exception {
return PutObjectArgs.builder()
.bucket((Strings.isBlank(bucketName)) ? bucketClient.getDefaultBucket() : bucketName)
.object(objectName)
.stream(file.getInputStream(), file.getSize(), -1)
.contentType(file.getContentType())
.build();
}
public Boolean checkFileIsExist(String objectName) {
return this.checkFileIsExist(bucketClient.getDefaultBucket(), objectName);
}
public Boolean checkFolderIsExist(String folderName) {
return this.checkFolderIsExist(bucketClient.getDefaultBucket(), folderName);
}
public Boolean checkFileIsExist(String bucketName, String objectName) {
try {
minioClient.statObject(
StatObjectArgs.builder().bucket(bucketName).object(objectName).build()
);
} catch (Exception e) {
return false;
}
return true;
}
public Boolean checkFolderIsExist(String bucketName, String folderName) {
try {
Iterable<Result<Item>> results = minioClient.listObjects(
ListObjectsArgs
.builder()
.bucket(bucketName)
.prefix(folderName)
.recursive(false)
.build());
for (Result<Item> result : results) {
Item item = result.get();
if (item.isDir() && folderName.equals(item.objectName())) {
return true;
}
}
} catch (Exception e) {
return false;
}
return true;
}
}
存储桶管理客户端
package kl.gayxzc.csr.cilent;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.RemoveBucketArgs;
import io.minio.SetBucketPolicyArgs;
import io.minio.messages.Bucket;
import kl.gayxzc.csr.constant.CsrErrorCode;
import kl.gayxzc.csr.constant.MinioConstant;
import kl.gayxzc.csr.exception.MinioException;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.util.List;
@Slf4j
@Component("bucketClient")
public class BucketClient {
private MinioClient minioClient;
private String defaultBucket;
@Value("${csr.minio.bucket-name}")
private String minioName;
@Autowired
public void setMinioClient(MinioClient minioClient) {
this.minioClient = minioClient;
}
public Boolean bucketExists(String bucketName) {
try {
return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
} catch (Exception e) {
log.error("bucket {} cannot found", bucketName, e);
throw new MinioException(CsrErrorCode.CHECK_ERROR);
}
}
public String getDefaultBucket() {
if (!StringUtils.hasText(defaultBucket)) {
defaultBucket = minioName;
if (!StringUtils.hasText(defaultBucket)) {
log.error("default bucket cannot be empty");
throw new MinioException(CsrErrorCode.MINIO_DEFAULT_ERROR);
}
}
return defaultBucket;
}
public void setDefaultBucket(String name) {
if (bucketExists(name)) {
this.defaultBucket = name;
return;
}
this.defaultBucket = minioName;
createBucket(this.defaultBucket);
if (!StringUtils.hasText(defaultBucket)) {
throw new MinioException(CsrErrorCode.MINIO_DEFAULT_ERROR);
}
}
public void createBucket(String bucketName) {
if (!bucketExists(bucketName)) {
try {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
} catch (Exception e) {
log.error("存储桶异常", e);
throw new MinioException(CsrErrorCode.BUCKET_ERROR);
}
}
log.warn("bucket {} has created", bucketName);
}
public void createBucket(String bucketName, String policy) {
if (!bucketExists(bucketName)) {
try {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
if (Strings.isBlank(policy)) {
policy = MinioConstant.READ_WRITE;
}
if (Strings.isNotBlank(policy)) {
String strategy = this.consolidationStrategy(bucketName, policy);
minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucketName).config(strategy).build());
}
} catch (Exception e) {
log.error("存储桶异常", e);
throw new MinioException(CsrErrorCode.BUCKET_ERROR);
}
}
log.warn("bucket {} has created", bucketName);
}
private String consolidationStrategy(String bucketName, String policy) {
String jsonStrategy = Strings.EMPTY;
if (MinioConstant.READ_ONLY.equals(policy)) {
jsonStrategy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\"],\"Resource\":[\"arn:aws:s3:::" + bucketName + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetObject\"],\"Resource\":[\"arn:aws:s3:::" + bucketName + "/*\"]}]}";
} else if (MinioConstant.WRITE_ONLY.equals(policy)) {
jsonStrategy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::" + bucketName + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:AbortMultipartUpload\",\"s3:DeleteObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\"],\"Resource\":[\"arn:aws:s3:::" + bucketName + "/*\"]}]}";
} else if (MinioConstant.READ_WRITE.equals(policy)) {
jsonStrategy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::" + bucketName + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:DeleteObject\",\"s3:GetObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\",\"s3:AbortMultipartUpload\"],\"Resource\":[\"arn:aws:s3:::" + bucketName + "/*\"]}]}";
} else {
try {
this.removeBucket(bucketName);
log.info("桶策略枚举值不合法,桶{}已删除", bucketName);
throw new MinioException(CsrErrorCode.POLICY_TYPE_ENUM_NOT_NULL);
} catch (Exception e) {
log.error("桶策略枚举值不合法", e);
}
}
return jsonStrategy;
}
public List<Bucket> getAllBuckets() {
try {
return minioClient.listBuckets();
} catch (Exception e) {
log.error("获取全部bucket信息失败异常", e);
throw new MinioException(CsrErrorCode.FAILED_ALL_INFORMATION_ERROR);
}
}
public void removeBucket(String bucketName) {
try {
minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
} catch (Exception e) {
log.error("删除bucket信息失败异常", e);
throw new MinioException(CsrErrorCode.REMOVE_BUCKET_ERROR);
}
}
}
常量定义
package kl.gayxzc.csr.constant;
public class MinioConstant {
public static final String DEFAULT_FILENAME_SEPARATOR = "@";
public static final String FILE_SEPARATOR_WIN = "\\";
public static final String FILE_SEPARATOR_UNIX = "/";
public static final String READ_ONLY = "READ_ONLY";
public static final String WRITE_ONLY = "WRITE_ONLY";
public static final String READ_WRITE = "READ_WRITE";
}
工具类定义
package kl.gayxzc.csr.utils;
import java.util.UUID;
public class UUIDUtils {
public static UUID randomUuid() {
return UUID.randomUUID();
}
public static String orgUuid() {
return randomUuid().toString();
}
public static String uuid() {
return orgUuid().replace("-", "");
}
}
package kl.gayxzc.csr.utils;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class DateUtils {
public static final String PATTERN_YYYYMMDD = "yyyyMMdd";
public static final DateTimeFormatter DTF_PATTERN_YYYYMMDD = DateTimeFormatter.ofPattern(PATTERN_YYYYMMDD);
public static final String PATTERN_YYYY_MM_DD = "yyyy-MM-dd";
public static final DateTimeFormatter DTF_PATTERN_YYYY_MM_DD = DateTimeFormatter.ofPattern(PATTERN_YYYY_MM_DD);
public static LocalDate now() {
return LocalDate.now();
}
public static String getNowDateStr() {
return now().format(DTF_PATTERN_YYYY_MM_DD);
}
public static Long getNowDateNumber() {
return Long.valueOf(getNowDateStr());
}
public static String getNowDateStr(String pattern) {
return now().format(DateTimeFormatter.ofPattern(pattern));
}
}