|
@@ -0,0 +1,338 @@
|
|
|
+package com.fdkankan.fusion.common.util;
|
|
|
+
|
|
|
+import com.fdkankan.fusion.config.MinIOConfig;
|
|
|
+import io.minio.*;
|
|
|
+import io.minio.http.Method;
|
|
|
+import io.minio.messages.Item;
|
|
|
+import lombok.SneakyThrows;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.beans.factory.InitializingBean;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+
|
|
|
+import javax.annotation.PostConstruct;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @ClassName UploadApiController
|
|
|
+ * @Description TODO
|
|
|
+ * @Author Ryan.
|
|
|
+ * @Emial_AND_OICQ ryan.tang@cyberwisdom.net AND 100792057
|
|
|
+ * @Date 2020/9/7 13:20
|
|
|
+ * @Version 1.0
|
|
|
+ **/
|
|
|
+@Component
|
|
|
+public class MinIoChunkUtils implements InitializingBean {
|
|
|
+
|
|
|
+ private static String url;
|
|
|
+
|
|
|
+ private static String accessKey;
|
|
|
+
|
|
|
+ private static String secretKey;
|
|
|
+
|
|
|
+
|
|
|
+ public static String chunkBucKet;
|
|
|
+
|
|
|
+ private static MinioClient minioClient;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 排序
|
|
|
+ */
|
|
|
+ public final static boolean SORT = true;
|
|
|
+ /**
|
|
|
+ * 不排序
|
|
|
+ */
|
|
|
+ public final static boolean NOT_SORT = false;
|
|
|
+ /**
|
|
|
+ * 默认过期时间(分钟)
|
|
|
+ */
|
|
|
+ private final static Integer DEFAULT_EXPIRY = 60;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void afterPropertiesSet() throws Exception {
|
|
|
+ minioClient = MinioClient.builder().endpoint(url).credentials(accessKey,secretKey).build();
|
|
|
+ //方便管理分片文件,则单独创建一个分片文件的存储桶
|
|
|
+ if (!isBucketExist(chunkBucKet)){
|
|
|
+ createBucket(chunkBucKet);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 初始化MinIo对象
|
|
|
+ * 非此工具类请勿使用该方法
|
|
|
+ */
|
|
|
+ @Autowired
|
|
|
+ MinIOConfig minIOConfig;
|
|
|
+ @PostConstruct
|
|
|
+ public void init(){
|
|
|
+ url = minIOConfig.getEndpoint();
|
|
|
+ accessKey =minIOConfig.getAccessKey();
|
|
|
+ secretKey = minIOConfig.getSecretKey();
|
|
|
+ chunkBucKet = minIOConfig.getBucketChunk();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 存储桶是否存在
|
|
|
+ * @param bucketName 存储桶名称
|
|
|
+ * @return true/false
|
|
|
+ */
|
|
|
+ @SneakyThrows
|
|
|
+ public static boolean isBucketExist(String bucketName){
|
|
|
+ return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建存储桶
|
|
|
+ * @param bucketName 存储桶名称
|
|
|
+ * @return true/false
|
|
|
+ */
|
|
|
+ @SneakyThrows
|
|
|
+ public static boolean createBucket(String bucketName){
|
|
|
+ minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取访问对象的外链地址
|
|
|
+ * @param bucketName 存储桶名称
|
|
|
+ * @param objectName 对象名称
|
|
|
+ * @param expiry 过期时间(分钟) 最大为7天 超过7天则默认最大值
|
|
|
+ * @return viewUrl
|
|
|
+ */
|
|
|
+ @SneakyThrows
|
|
|
+ public static String getObjectUrl(String bucketName,String objectName,Integer expiry){
|
|
|
+ expiry = expiryHandle(expiry);
|
|
|
+ return minioClient.getPresignedObjectUrl(
|
|
|
+ GetPresignedObjectUrlArgs.builder()
|
|
|
+ .method(Method.GET)
|
|
|
+ .bucket(bucketName)
|
|
|
+ .object(objectName)
|
|
|
+ .expiry(expiry)
|
|
|
+ .build()
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建上传文件对象的外链
|
|
|
+ * @param bucketName 存储桶名称
|
|
|
+ * @param objectName 欲上传文件对象的名称
|
|
|
+ * @param expiry 过期时间(分钟) 最大为7天 超过7天则默认最大值
|
|
|
+ * @return uploadUrl
|
|
|
+ */
|
|
|
+ @SneakyThrows
|
|
|
+ public static String createUploadUrl(String bucketName,String objectName,Integer expiry){
|
|
|
+ expiry = expiryHandle(expiry);
|
|
|
+ return minioClient.getPresignedObjectUrl(
|
|
|
+ GetPresignedObjectUrlArgs.builder()
|
|
|
+ .method(Method.PUT)
|
|
|
+ .bucket(bucketName)
|
|
|
+ .object(objectName)
|
|
|
+ .expiry(expiry)
|
|
|
+ .build()
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建上传文件对象的外链
|
|
|
+ * @param bucketName 存储桶名称
|
|
|
+ * @param objectName 欲上传文件对象的名称
|
|
|
+ * @return uploadUrl
|
|
|
+ */
|
|
|
+ public static String createUploadUrl(String bucketName,String objectName){
|
|
|
+ return createUploadUrl(bucketName,objectName,DEFAULT_EXPIRY);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 批量创建分片上传外链
|
|
|
+ * @param bucketName 存储桶名称
|
|
|
+ * @param objectMD5 欲上传分片文件主文件的MD5
|
|
|
+ * @param chunkCount 分片数量
|
|
|
+ * @return uploadChunkUrls
|
|
|
+ */
|
|
|
+ public static List<String> createUploadChunkUrlList(String bucketName,String objectMD5,Integer chunkCount){
|
|
|
+ if (null == bucketName){
|
|
|
+ bucketName = chunkBucKet;
|
|
|
+ }
|
|
|
+ if (null == objectMD5){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ objectMD5 += "/";
|
|
|
+ if(null == chunkCount || 0 == chunkCount){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ List<String> urlList = new ArrayList<>(chunkCount);
|
|
|
+ for (int i = 1; i <= chunkCount; i++){
|
|
|
+ String objectName = objectMD5 + i + ".chunk";
|
|
|
+ urlList.add(createUploadUrl(bucketName,objectName,DEFAULT_EXPIRY));
|
|
|
+ }
|
|
|
+ return urlList;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建指定序号的分片文件上传外链
|
|
|
+ * @param bucketName 存储桶名称
|
|
|
+ * @param objectMD5 欲上传分片文件主文件的MD5
|
|
|
+ * @param partNumber 分片序号
|
|
|
+ * @return uploadChunkUrl
|
|
|
+ */
|
|
|
+ public static String createUploadChunkUrl(String bucketName,String objectMD5,String partNumber){
|
|
|
+ if (null == bucketName){
|
|
|
+ bucketName = chunkBucKet;
|
|
|
+ }
|
|
|
+ if (null == objectMD5){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ objectMD5 += "/" + partNumber + ".chunk";
|
|
|
+ return createUploadUrl(bucketName,objectMD5,DEFAULT_EXPIRY);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取对象文件名称列表
|
|
|
+ * @param bucketName 存储桶名称
|
|
|
+ * @param prefix 对象名称前缀
|
|
|
+ * @param sort 是否排序(升序)
|
|
|
+ * @return objectNames
|
|
|
+ */
|
|
|
+ @SneakyThrows
|
|
|
+ public static List<String> listObjectNames(String bucketName,String prefix,Boolean sort){
|
|
|
+ ListObjectsArgs listObjectsArgs;
|
|
|
+ if(null == prefix){
|
|
|
+ listObjectsArgs = ListObjectsArgs.builder()
|
|
|
+ .bucket(bucketName)
|
|
|
+ .recursive(true)
|
|
|
+ .build();
|
|
|
+ }else {
|
|
|
+ listObjectsArgs = ListObjectsArgs.builder()
|
|
|
+ .bucket(bucketName)
|
|
|
+ .prefix(prefix)
|
|
|
+ .recursive(true)
|
|
|
+ .build();
|
|
|
+ }
|
|
|
+ Iterable<Result<Item>> chunks = minioClient.listObjects(listObjectsArgs);
|
|
|
+ List<String> chunkPaths = new ArrayList<>();
|
|
|
+ for (Result<Item> item : chunks){
|
|
|
+ chunkPaths.add(item.get().objectName());
|
|
|
+ }
|
|
|
+ if (sort){
|
|
|
+ return chunkPaths.stream().distinct().collect(Collectors.toList());
|
|
|
+ }
|
|
|
+ return chunkPaths;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取对象文件名称列表
|
|
|
+ * @param bucketName 存储桶名称
|
|
|
+ * @param prefix 对象名称前缀
|
|
|
+ * @return objectNames
|
|
|
+ */
|
|
|
+ public static List<String> listObjectNames(String bucketName,String prefix){
|
|
|
+ return listObjectNames(bucketName, prefix, NOT_SORT);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取分片文件名称列表
|
|
|
+ * @param bucketName 存储桶名称
|
|
|
+ * @param ObjectMd5 对象Md5
|
|
|
+ * @return objectChunkNames
|
|
|
+ */
|
|
|
+ public static List<String> listChunkObjectNames(String bucketName,String ObjectMd5){
|
|
|
+ if (null == bucketName){
|
|
|
+ bucketName = chunkBucKet;
|
|
|
+ }
|
|
|
+ if (null == ObjectMd5){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return listObjectNames(bucketName,ObjectMd5,SORT);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取分片名称地址HashMap key=分片序号 value=分片文件地址
|
|
|
+ * @param bucketName 存储桶名称
|
|
|
+ * @param ObjectMd5 对象Md5
|
|
|
+ * @return objectChunkNameMap
|
|
|
+ */
|
|
|
+ public static Map<Integer,String> mapChunkObjectNames(String bucketName, String ObjectMd5){
|
|
|
+ if (null == bucketName){
|
|
|
+ bucketName = chunkBucKet;
|
|
|
+ }
|
|
|
+ if (null == ObjectMd5){
|
|
|
+ return new HashMap<>();
|
|
|
+ }
|
|
|
+ List<String> chunkPaths = listObjectNames(bucketName,ObjectMd5);
|
|
|
+ if (null == chunkPaths || chunkPaths.size() == 0){
|
|
|
+ return new HashMap<>();
|
|
|
+ }
|
|
|
+ Map<Integer,String> chunkMap = new HashMap<>(chunkPaths.size());
|
|
|
+ for (String chunkName : chunkPaths) {
|
|
|
+ Integer partNumber = Integer.parseInt(chunkName.substring(chunkName.indexOf("/") + 1,chunkName.lastIndexOf(".")));
|
|
|
+ chunkMap.put(partNumber,chunkName);
|
|
|
+ }
|
|
|
+ return chunkMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 合并分片文件成对象文件
|
|
|
+ * @param chunkBucKetName 分片文件所在存储桶名称
|
|
|
+ * @param composeBucketName 合并后的对象文件存储的存储桶名称
|
|
|
+ * @param chunkNames 分片文件名称集合
|
|
|
+ * @param objectName 合并后的对象文件名称
|
|
|
+ * @return true/false
|
|
|
+ */
|
|
|
+ @SneakyThrows
|
|
|
+ public static boolean composeObject(String chunkBucKetName,String composeBucketName,List<String> chunkNames,String objectName){
|
|
|
+ if (null == chunkBucKetName){
|
|
|
+ chunkBucKetName = chunkBucKet;
|
|
|
+ }
|
|
|
+ List<ComposeSource> sourceObjectList = new ArrayList<>(chunkNames.size());
|
|
|
+ for (String chunk : chunkNames){
|
|
|
+ sourceObjectList.add(
|
|
|
+ ComposeSource.builder()
|
|
|
+ .bucket(chunkBucKetName)
|
|
|
+ .object(chunk)
|
|
|
+ .build()
|
|
|
+ );
|
|
|
+ }
|
|
|
+ minioClient.composeObject(
|
|
|
+ ComposeObjectArgs.builder()
|
|
|
+ .bucket(composeBucketName)
|
|
|
+ .object(objectName)
|
|
|
+ .sources(sourceObjectList)
|
|
|
+ .build()
|
|
|
+ );
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 合并分片文件成对象文件
|
|
|
+ * @param bucketName 存储桶名称
|
|
|
+ * @param chunkNames 分片文件名称集合
|
|
|
+ * @param objectName 合并后的对象文件名称
|
|
|
+ * @return true/false
|
|
|
+ */
|
|
|
+ public static boolean composeObject(String bucketName,List<String> chunkNames,String objectName){
|
|
|
+ return composeObject(chunkBucKet,bucketName,chunkNames,objectName);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将分钟数转换为秒数
|
|
|
+ * @param expiry 过期时间(分钟数)
|
|
|
+ * @return expiry
|
|
|
+ */
|
|
|
+ private static int expiryHandle(Integer expiry){
|
|
|
+ expiry = expiry * 60;
|
|
|
+ if (expiry > 604800){
|
|
|
+ return 604800;
|
|
|
+ }
|
|
|
+ return expiry;
|
|
|
+ }
|
|
|
+ public static String buZero(Integer size,Integer index){
|
|
|
+ String numStr = String.valueOf(size);
|
|
|
+ return StringUtils.leftPad(String.valueOf(index),numStr.length()+1,'0');
|
|
|
+ }
|
|
|
+}
|