package com.ard.utils.minio; import com.ard.utils.util.StringUtils; import com.ard.utils.util.IdUtils; import io.minio.*; import io.minio.http.Method; import io.minio.messages.*; import lombok.extern.slf4j.Slf4j; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; /** * @Description: minio工具类 * @ClassName: MinioUtil * @Author: 刘苏义 * @Date: 2023年08月25日14:03:00 **/ @Slf4j(topic = "minio") public class MinioUtil { private volatile static MinioClient minioClient; public static String domainUrl; public static String accessKey; public static String secretKey; private MinioUtil() { } public MinioUtil(String domainUrl, String accessKey, String secretKey) { this.domainUrl = domainUrl; this.accessKey = accessKey; this.secretKey = secretKey; creatMinioClient(); } /** * 获取minio客户端实例 * * @return {@link MinioClient} */ public static MinioClient creatMinioClient() { if (minioClient == null) { synchronized (MinioUtil.class) { if (minioClient == null) { minioClient = MinioClient.builder() .endpoint(domainUrl) .credentials(accessKey, secretKey) .build(); } } } return minioClient; } /** * 判断桶是否存在 */ public static boolean exitsBucket(String bucket) { boolean found = false; try { if (StringUtils.isEmpty(bucket)) { return false; } BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder().bucket(bucket).build(); found = minioClient.bucketExists(bucketExistsArgs); } catch (Exception ex) { log.error("minio判断桶存在异常:", ex.getMessage()); } return found; } /** * 创建桶,并设置桶策略为公共 */ public static boolean createBucket(String bucket) { try { if (StringUtils.isEmpty(bucket)) { return false; } /*创建桶*/ MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder().bucket(bucket).build(); minioClient.makeBucket(makeBucketArgs); /*设置策略*/ String sb = "{\"Version\":\"2012-10-17\"," + "\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":" + "{\"AWS\":[\"*\"]},\"Action\":[\"s3:ListBucket\",\"s3:ListBucketMultipartUploads\"," + "\"s3:GetBucketLocation\"],\"Resource\":[\"arn:aws:s3:::" + bucket + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:PutObject\",\"s3:AbortMultipartUpload\",\"s3:DeleteObject\",\"s3:GetObject\",\"s3:ListMultipartUploadParts\"],\"Resource\":[\"arn:aws:s3:::" + bucket + "/*\"]}]}"; SetBucketPolicyArgs setBucketPolicyArgs = SetBucketPolicyArgs.builder() .bucket(bucket) .config(sb) .build(); /*设置通知mqtt*/ //设置mqtt主题 NotificationConfiguration config = new NotificationConfiguration(); List queueConfigurations = new ArrayList<>(); QueueConfiguration queueConfiguration = new QueueConfiguration(); queueConfiguration.setQueue("arn:minio:sqs::_:mqtt"); //设置事件 List events = new ArrayList<>(); events.add(EventType.OBJECT_REMOVED_ANY); events.add(EventType.OBJECT_CREATED_ANY); queueConfiguration.setEvents(events); queueConfigurations.add(queueConfiguration); config.setQueueConfigurationList(queueConfigurations); SetBucketNotificationArgs setBucketNotificationArgs = SetBucketNotificationArgs.builder() .bucket(bucket) .config(config).build(); minioClient.setBucketPolicy(setBucketPolicyArgs); minioClient.setBucketNotification(setBucketNotificationArgs); return true; } catch (Exception ex) { log.error("minio创建桶异常:", ex.getMessage()); return false; } } /** * 删除一个桶 * * @param bucket 桶名称 */ public static boolean removeBucket(String bucket) { try { boolean found = exitsBucket(bucket); if (found) { Iterable> myObjects = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucket).build()); for (Result result : myObjects) { Item item = result.get(); //有对象文件,则删除失败 if (item.size() > 0) { return false; } } // 删除`bucketName`存储桶,注意,只有存储桶为空时才能删除成功。 minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucket).build()); found = exitsBucket(bucket); return !found; } } catch (Exception ex) { log.error("删除桶异常:" + ex.getMessage()); } return false; } /** * 查询所有桶文件 * * @return */ public static List getListBuckets() { try { return minioClient.listBuckets(); } catch (Exception e) { e.printStackTrace(); } return Collections.emptyList(); } /** * 生成一个GET请求的带有失效时间的分享链接。 * 失效时间默认是7天。 * * @param bucket 存储桶名称 * @param object 存储桶里的对象名称 * @param expires 失效时间(以秒为单位),默认是7天,不得大于七天 * @return */ public static String getObjectWithExpired(String bucket, String object, Integer expires, TimeUnit timeUnit) { String url = ""; if (exitsBucket(bucket)) { try { GetPresignedObjectUrlArgs getPresignedObjectUrlArgs = GetPresignedObjectUrlArgs.builder() .method(Method.GET) .bucket(bucket) .object(object) .expiry(expires, timeUnit) .build(); url = minioClient.getPresignedObjectUrl(getPresignedObjectUrlArgs); } catch (Exception ex) { log.error("minio生成失效url异常", ex.getMessage()); } } else { createBucket(bucket); } return url; } /** * @描述 上传MultipartFile文件返回url * @参数 [bucketName, file] * @返回值 java.lang.String * @创建人 刘苏义 * @创建时间 2023/5/18 12:16 * @修改人和其它信息 */ public static String putObjectAndGetUrl(String bucket, MultipartFile file) { if (!exitsBucket(bucket)) { createBucket(bucket); } //判断文件是否为空 if (null == file || 0 == file.getSize()) { log.error("上传minio文件服务器错误,上传文件为空"); } //文件名 String originalFilename = file.getOriginalFilename(); //新的文件名 String fileName = IdUtils.fastSimpleUUID() + "_" + originalFilename; try { InputStream inputStream = file.getInputStream(); /*上传对象*/ PutObjectArgs putObjectArgs = PutObjectArgs .builder() .bucket(bucket) .object(fileName) .stream(inputStream, file.getSize(), -1) .contentType(file.getContentType()) .build(); minioClient.putObject(putObjectArgs); inputStream.close(); /*获取url*/ GetPresignedObjectUrlArgs getPresignedObjectUrlArgs = GetPresignedObjectUrlArgs .builder() .bucket(bucket) .object(fileName) .method(Method.GET) .build(); String presignedObjectUrl = minioClient.getPresignedObjectUrl(getPresignedObjectUrlArgs); String ObjectUrl = presignedObjectUrl.substring(0, presignedObjectUrl.indexOf("?")); return ObjectUrl; } catch (Exception ex) { log.error("上传对象返回url异常:" + ex.getMessage()); } return ""; } /** * @描述 上传MultipartFile文件返回url * @参数 [bucketName, file] * @返回值 java.lang.String * @创建人 刘苏义 * @创建时间 2023/5/18 12:16 * @修改人和其它信息 */ public static String putObjectAndGetUrl(String bucket, String folder, MultipartFile file) { if (!exitsBucket(bucket)) { createBucket(bucket); } //判断文件是否为空 if (null == file || 0 == file.getSize()) { log.error("上传minio文件服务器错误,上传文件为空"); } //文件名 String originalFilename = file.getOriginalFilename(); //新的文件名 String fileName = folder + "/" + IdUtils.fastSimpleUUID() + "_" + originalFilename; try { InputStream inputStream = file.getInputStream(); /*上传对象*/ PutObjectArgs putObjectArgs = PutObjectArgs .builder() .bucket(bucket) .object(fileName) .stream(inputStream, file.getSize(), -1) .contentType(file.getContentType()) .build(); minioClient.putObject(putObjectArgs); inputStream.close(); /*获取url*/ GetPresignedObjectUrlArgs getPresignedObjectUrlArgs = GetPresignedObjectUrlArgs .builder() .bucket(bucket) .object(fileName) .method(Method.GET) .build(); String presignedObjectUrl = minioClient.getPresignedObjectUrl(getPresignedObjectUrlArgs); String ObjectUrl = presignedObjectUrl.substring(0, presignedObjectUrl.indexOf("?")); return ObjectUrl; } catch (Exception ex) { log.error("上传对象返回url异常:" + ex.getMessage()); } return ""; } /** * 删除文件 * * @param bucket 桶名称 * @param object 对象名称 * @return boolean */ public static boolean removeObject(String bucket, String object) { try { boolean exsit = exitsBucket(bucket); if (exsit) { RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(bucket).object(object).build(); minioClient.removeObject(removeObjectArgs); return true; } } catch (Exception e) { log.error("removeObject", e); } return false; } /** * 批量删除文件 * * @param objectList 对象名称列表 * @return boolean */ public static boolean removeObjects(String bucket, List objectList) { if (exitsBucket(bucket)) { try { List objects = new LinkedList<>(); for (String str : objectList) { objects.add(new DeleteObject(str)); } RemoveObjectsArgs removeObjectsArgs = RemoveObjectsArgs.builder().bucket(bucket).objects(objects).build(); Iterable> results = minioClient.removeObjects(removeObjectsArgs); /*删除完遍历结果,否则删不掉*/ for (Result result : results) { DeleteError error = result.get(); log.error("Error in deleting object " + error.objectName() + "; " + error.message()); } return true; } catch (Exception ex) { log.error("minio批量删除文件异常", ex.getMessage()); } } return false; } /** * 获取单个桶中的所有文件对象名称 * * @param bucket 桶名称 * @return {@link List}<{@link String}> */ public static List getBucketObjectName(String bucket) { boolean exsit = exitsBucket(bucket); if (exsit) { List listObjetcName = new ArrayList<>(); try { ListObjectsArgs listObjectsArgs = ListObjectsArgs.builder().bucket(bucket).build(); Iterable> myObjects = minioClient.listObjects(listObjectsArgs); for (Result result : myObjects) { Item item = result.get(); listObjetcName.add(item.objectName()); } return listObjetcName; } catch (Exception ex) { log.error("minio获取桶下对象异常:" + ex.getMessage()); } } return null; } /** * 获取单个桶中的所有文件对象名称 * * @param bucket 桶名称 * @param prefix 前缀 * @return {@link List}<{@link String}> */ public static List getBucketObjectName(String bucket, String prefix) { boolean exsit = exitsBucket(bucket); if (exsit) { List listObjetcName = new ArrayList<>(); try { ListObjectsArgs listObjectsArgs = ListObjectsArgs.builder().prefix(prefix).bucket(bucket).build(); Iterable> myObjects = minioClient.listObjects(listObjectsArgs); for (Result result : myObjects) { Item item = result.get(); listObjetcName.add(item.objectName()); } return listObjetcName; } catch (Exception ex) { log.error("minio获取桶下对象异常:" + ex.getMessage()); } } return null; } /** * 获取某个桶下某个对象的URL * * @param bucket 桶名称 * @param object 对象名 (文件夹名 + 文件名) * @return */ public static String getBucketObjectUrl(String bucket, String object) { try { if (!exitsBucket(bucket)) { return ""; } GetPresignedObjectUrlArgs getPresignedObjectUrlArgs = GetPresignedObjectUrlArgs .builder() .bucket(bucket) .object(object) .method(Method.GET) .build(); String presignedObjectUrl = minioClient.getPresignedObjectUrl(getPresignedObjectUrlArgs); String ObjectUrl = presignedObjectUrl.substring(0, presignedObjectUrl.indexOf("?")); return ObjectUrl; } catch (Exception ex) { log.error("minio获取对象URL异常" + ex.getMessage()); } return ""; } /** * 上传对象-stream * * @param bucket bucket名称 * @param object ⽂件名称 * @param stream ⽂件流 * @param size ⼤⼩ * @param contextType 类型 Image/jpeg 浏览器可以直接打开,否则下载 */ public static boolean uploadObject(String bucket, String object, InputStream stream, long size, String contextType) { try { if (!exitsBucket(bucket)) { createBucket(bucket); } PutObjectArgs putObjectArgs = PutObjectArgs.builder() .bucket(bucket) .object(object) .stream(stream, size, -1) .contentType(contextType) .build(); ObjectWriteResponse objectWriteResponse = minioClient.putObject(putObjectArgs); return true; } catch (Exception ex) { log.error("minio上传文件(通过stream)异常" + ex.getMessage()); return false; } } /** * 上传对象-File * * @param bucket bucket名称 * @param object ⽂件名称 * @param file ⽂件 * @param contextType 类型 Image/jpeg 浏览器可以直接打开,否则下载 */ public static boolean uploadObject(String bucket, String object, File file, String contextType) { try { if (!exitsBucket(bucket)) { createBucket(bucket); } FileInputStream fileInputStream = new FileInputStream(file); PutObjectArgs putObjectArgs = PutObjectArgs.builder() .bucket(bucket) .object(object) .stream(fileInputStream, file.length(), -1) .contentType(contextType) .build(); ObjectWriteResponse objectWriteResponse = minioClient.putObject(putObjectArgs); return true; } catch (Exception ex) { log.error("minio上传文件(通过File)异常" + ex.getMessage()); return false; } } /** * 上传对象-MultipartFile * * @param bucket bucket名称 * @param object ⽂件名称 * @param multipartFile ⽂件 * @param contextType 类型 Image/jpeg 浏览器可以直接打开,否则下载 */ public static boolean uploadObject(String bucket, String object, MultipartFile multipartFile, String contextType) { try { if (!exitsBucket(bucket)) { createBucket(bucket); } InputStream inputStream = multipartFile.getInputStream(); PutObjectArgs putObjectArgs = PutObjectArgs.builder() .bucket(bucket) .object(object) .stream(inputStream, multipartFile.getSize(), -1) .contentType(contextType) .build(); ObjectWriteResponse objectWriteResponse = minioClient.putObject(putObjectArgs); return true; } catch (Exception ex) { log.error("minio上传文件(通过File)异常" + ex.getMessage()); return false; } } /** * 上传对象,用multipartFile名称作为对象名 * * @param bucket bucket名称 * @param multipartFile ⽂件 * @param contextType 类型 Image/jpeg 浏览器可以直接打开,否则下载 */ public static boolean uploadObject(String bucket, MultipartFile multipartFile, String contextType) { try { if (!exitsBucket(bucket)) { createBucket(bucket); } if (multipartFile == null) { log.error("上传文件为空"); return false; } String objectName = multipartFile.getOriginalFilename(); InputStream inputStream = multipartFile.getInputStream(); PutObjectArgs putObjectArgs = PutObjectArgs.builder() .bucket(bucket) .object(objectName) .stream(inputStream, multipartFile.getSize(), -1) .contentType(contextType) .build(); minioClient.putObject(putObjectArgs); return true; } catch (Exception ex) { log.error("minio上传文件(通过File)异常" + ex.getMessage()); return false; } } /** * 上传对象-通过本地路径 * * @param bucket 桶名称 * @param object 对象名称 * @param localFilePathName 文件路径 * @return boolean */ public static boolean uploadObject(String bucket, String object, String localFilePathName, String contextType) { try { if (!exitsBucket(bucket)) { createBucket(bucket); } File file = new File(localFilePathName); if (!file.exists()) { log.debug("文件不存在"); return false; } UploadObjectArgs uploadObjectArgs = UploadObjectArgs.builder() .bucket(bucket) .object(object) .filename(localFilePathName) .contentType(contextType) .build(); ObjectWriteResponse objectWriteResponse = minioClient.uploadObject(uploadObjectArgs); return true; } catch (Exception e) { log.error("minio upload object file error " + e.getMessage()); return false; } } /** * @描述 获取桶中所有对象 * @参数 [bucketName] * @返回值 java.lang.Iterable> * @创建人 刘苏义 * @创建时间 2023/2/6 10:32 * @修改人和其它信息 */ public static Iterable> getObjectsByBucket(String bucketName) { Iterable> listObjects = minioClient.listObjects(ListObjectsArgs.builder() .bucket(bucketName) .recursive(true) .build()); return listObjects; } /** * @描述 获取桶中所有对象 * @参数 [bucketName, prefix] * @返回值 java.lang.Iterable> * @创建人 刘苏义 * @创建时间 2023/2/6 10:32 * @修改人和其它信息 */ public static Iterable> getObjectsByBucket(String bucketName, String prefix) { Iterable> listObjects = minioClient.listObjects(ListObjectsArgs.builder() .bucket(bucketName) .prefix(prefix) .recursive(true) .build()); return listObjects; } }