mirror of
https://gitee.com/lxp135/minio-plus.git
synced 2025-12-06 08:58:25 +08:00
feat(thumbnail-generator): The first visit to the thumbnail is to generate a thumbnail image
This commit is contained in:
parent
f743c1f240
commit
83b528a0c2
@ -8,8 +8,9 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* MinioPlus配置类
|
* MinioPlus配置类
|
||||||
|
*
|
||||||
* @author contact@liuxp.me
|
* @author contact@liuxp.me
|
||||||
* @since 2024/05/22
|
* @since 2024/05/22
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@ -89,7 +90,11 @@ public class MinioPlusProperties {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否开启缩略图。默认为true
|
* 是否开启缩略图。默认为true
|
||||||
|
*
|
||||||
|
* @since 2024-06-14 15:47:46
|
||||||
|
* feature 缩略图懒生成
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
private boolean enable = true;
|
private boolean enable = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -54,21 +54,20 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传任务初始化
|
* 上传任务初始化
|
||||||
*
|
* <p>
|
||||||
* 1.当前用户或其他用户上传过,且已完成,秒传,新增文件元数据
|
* 1.当前用户或其他用户上传过,且已完成,秒传,新增文件元数据
|
||||||
* 2.当前用户上传过,未完成,断点续传
|
* 2.当前用户上传过,未完成,断点续传
|
||||||
* 3.其他用户上传过,未完成,断点续传,新增文件元数据
|
* 3.其他用户上传过,未完成,断点续传,新增文件元数据
|
||||||
* 4.从未上传过,下发上传链接,新增文件元数据
|
* 4.从未上传过,下发上传链接,新增文件元数据
|
||||||
*
|
*
|
||||||
* @param fileMd5 文件md5
|
* @param fileMd5 文件md5
|
||||||
* @param fullFileName 文件名(含扩展名)
|
* @param fullFileName 文件名(含扩展名)
|
||||||
* @param fileSize 文件长度
|
* @param fileSize 文件长度
|
||||||
* @param isPrivate 是否私有 false:否 true:是
|
* @param isPrivate 是否私有 false:否 true:是
|
||||||
*
|
|
||||||
* @return {@link FileCheckResultVo}
|
* @return {@link FileCheckResultVo}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public FileCheckResultVo init(String fileMd5, String fullFileName, long fileSize, Boolean isPrivate,String userId) {
|
public FileCheckResultVo init(String fileMd5, String fullFileName, long fileSize, Boolean isPrivate, String userId) {
|
||||||
|
|
||||||
// 根据MD5查询文件是否已上传过
|
// 根据MD5查询文件是否已上传过
|
||||||
FileMetadataInfoDTO searchDTO = new FileMetadataInfoDTO();
|
FileMetadataInfoDTO searchDTO = new FileMetadataInfoDTO();
|
||||||
@ -78,10 +77,10 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
FileMetadataInfoSaveDTO saveDTO = new FileMetadataInfoSaveDTO();
|
FileMetadataInfoSaveDTO saveDTO = new FileMetadataInfoSaveDTO();
|
||||||
CreateUploadUrlReqBO bo = new CreateUploadUrlReqBO();
|
CreateUploadUrlReqBO bo = new CreateUploadUrlReqBO();
|
||||||
|
|
||||||
if(CollUtil.isNotEmpty(list)){
|
if (CollUtil.isNotEmpty(list)) {
|
||||||
// 1.当前用户或其他用户上传过,且已完成,秒传,新增文件元数据
|
// 1.当前用户或其他用户上传过,且已完成,秒传,新增文件元数据
|
||||||
for (FileMetadataInfoVo fileMetadataInfoVo : list) {
|
for (FileMetadataInfoVo fileMetadataInfoVo : list) {
|
||||||
if(fileMetadataInfoVo.getIsFinished()){
|
if (fileMetadataInfoVo.getIsFinished()) {
|
||||||
// 秒传
|
// 秒传
|
||||||
saveDTO.setFileKey(IdUtil.fastSimpleUUID()); // 文件KEY
|
saveDTO.setFileKey(IdUtil.fastSimpleUUID()); // 文件KEY
|
||||||
saveDTO.setFileMd5(fileMd5); // 文件md5
|
saveDTO.setFileMd5(fileMd5); // 文件md5
|
||||||
@ -109,13 +108,13 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
|
|
||||||
boolean isSelf = userUploaded.isPresent();
|
boolean isSelf = userUploaded.isPresent();
|
||||||
|
|
||||||
if(!isSelf){
|
if (!isSelf) {
|
||||||
uploadingMetadata = list.stream()
|
uploadingMetadata = list.stream()
|
||||||
.filter(FileMetadataInfoVo::getIsFinished)
|
.filter(FileMetadataInfoVo::getIsFinished)
|
||||||
.findAny()
|
.findAny()
|
||||||
.orElseGet(() -> list.stream()
|
.orElseGet(() -> list.stream()
|
||||||
.filter(item -> !item.getIsFinished()).findFirst().get());
|
.filter(item -> !item.getIsFinished()).findFirst().get());
|
||||||
}else{
|
} else {
|
||||||
uploadingMetadata = userUploaded.get();
|
uploadingMetadata = userUploaded.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +122,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
bo.setIsSequel(Boolean.TRUE);
|
bo.setIsSequel(Boolean.TRUE);
|
||||||
CreateUploadUrlRespBO respBO = this.breakResume(uploadingMetadata);
|
CreateUploadUrlRespBO respBO = this.breakResume(uploadingMetadata);
|
||||||
|
|
||||||
if(!isSelf){
|
if (!isSelf) {
|
||||||
// 3.其他用户上传过,未完成,断点续传,新增文件元数据
|
// 3.其他用户上传过,未完成,断点续传,新增文件元数据
|
||||||
// 插入自己的元数据
|
// 插入自己的元数据
|
||||||
BeanUtils.copyProperties(uploadingMetadata, saveDTO);
|
BeanUtils.copyProperties(uploadingMetadata, saveDTO);
|
||||||
@ -134,9 +133,9 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
FileMetadataInfoVo metadataInfoVo = metadataRepository.save(saveDTO);
|
FileMetadataInfoVo metadataInfoVo = metadataRepository.save(saveDTO);
|
||||||
|
|
||||||
return this.buildResult(metadataInfoVo, respBO.getParts(), respBO.getPartCount(), Boolean.FALSE);
|
return this.buildResult(metadataInfoVo, respBO.getParts(), respBO.getPartCount(), Boolean.FALSE);
|
||||||
}else{
|
} else {
|
||||||
// 2.当前用户上传过,未完成,断点续传
|
// 2.当前用户上传过,未完成,断点续传
|
||||||
if(CollUtil.isNotEmpty(respBO.getParts()) && !respBO.getUploadTaskId().equals(uploadingMetadata.getUploadTaskId())){
|
if (CollUtil.isNotEmpty(respBO.getParts()) && !respBO.getUploadTaskId().equals(uploadingMetadata.getUploadTaskId())) {
|
||||||
// 原uploadTaskId失效时,同时更新原记录
|
// 原uploadTaskId失效时,同时更新原记录
|
||||||
uploadingMetadata.setUploadTaskId(respBO.getUploadTaskId());
|
uploadingMetadata.setUploadTaskId(respBO.getUploadTaskId());
|
||||||
FileMetadataInfoUpdateDTO updateDTO = new FileMetadataInfoUpdateDTO();
|
FileMetadataInfoUpdateDTO updateDTO = new FileMetadataInfoUpdateDTO();
|
||||||
@ -148,7 +147,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
|
|
||||||
return this.buildResult(uploadingMetadata, respBO.getParts(), respBO.getPartCount(), Boolean.FALSE);
|
return this.buildResult(uploadingMetadata, respBO.getParts(), respBO.getPartCount(), Boolean.FALSE);
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
// 4.从未上传过,下发上传链接,新增文件元数据
|
// 4.从未上传过,下发上传链接,新增文件元数据
|
||||||
|
|
||||||
bo.setFileMd5(fileMd5);
|
bo.setFileMd5(fileMd5);
|
||||||
@ -157,7 +156,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
|
|
||||||
CreateUploadUrlRespBO createUploadUrlRespBO = this.createUploadUrl(bo);
|
CreateUploadUrlRespBO createUploadUrlRespBO = this.createUploadUrl(bo);
|
||||||
|
|
||||||
FileMetadataInfoVo metadataInfo = saveMetadataInfo(saveDTO, createUploadUrlRespBO, fileMd5, fullFileName, fileSize, isPrivate, userId);
|
FileMetadataInfoVo metadataInfo = saveMetadataInfo(saveDTO, createUploadUrlRespBO, fileMd5, fullFileName, fileSize, isPrivate, userId);
|
||||||
|
|
||||||
return this.buildResult(metadataInfo, createUploadUrlRespBO.getParts(), createUploadUrlRespBO.getPartCount(), Boolean.FALSE);
|
return this.buildResult(metadataInfo, createUploadUrlRespBO.getParts(), createUploadUrlRespBO.getPartCount(), Boolean.FALSE);
|
||||||
}
|
}
|
||||||
@ -204,13 +203,13 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
/**
|
/**
|
||||||
* 保存文件源信息
|
* 保存文件源信息
|
||||||
*
|
*
|
||||||
* @param saveDTO 元数据保存实体类
|
* @param saveDTO 元数据保存实体类
|
||||||
* @param createUploadUrlRespBO 上传链接参数
|
* @param createUploadUrlRespBO 上传链接参数
|
||||||
* @param fileMd5 文件md5
|
* @param fileMd5 文件md5
|
||||||
* @param fullFileName 文件名(含扩展名)
|
* @param fullFileName 文件名(含扩展名)
|
||||||
* @param fileSize 文件长度
|
* @param fileSize 文件长度
|
||||||
* @param isPrivate 是否私有 false:否 true:是
|
* @param isPrivate 是否私有 false:否 true:是
|
||||||
* @param userId 用户编号
|
* @param userId 用户编号
|
||||||
* @return {@link FileMetadataInfoVo}
|
* @return {@link FileMetadataInfoVo}
|
||||||
*/
|
*/
|
||||||
private FileMetadataInfoVo saveMetadataInfo(FileMetadataInfoSaveDTO saveDTO, CreateUploadUrlRespBO createUploadUrlRespBO,
|
private FileMetadataInfoVo saveMetadataInfo(FileMetadataInfoSaveDTO saveDTO, CreateUploadUrlRespBO createUploadUrlRespBO,
|
||||||
@ -259,7 +258,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
* @return {@link Boolean}
|
* @return {@link Boolean}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public CompleteResultVo complete(String fileKey, List<String> partMd5List,String userId) {
|
public CompleteResultVo complete(String fileKey, List<String> partMd5List, String userId) {
|
||||||
|
|
||||||
CompleteResultVo completeResultVo = new CompleteResultVo();
|
CompleteResultVo completeResultVo = new CompleteResultVo();
|
||||||
|
|
||||||
@ -271,24 +270,24 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
|
|
||||||
FileMetadataInfoVo metadata = metadataRepository.one(searchDto);
|
FileMetadataInfoVo metadata = metadataRepository.one(searchDto);
|
||||||
|
|
||||||
if(metadata == null){
|
if (metadata == null) {
|
||||||
log.error(fileKey+MinioPlusErrorCode.FILE_EXIST_FAILED.getMessage());
|
log.error(fileKey + MinioPlusErrorCode.FILE_EXIST_FAILED.getMessage());
|
||||||
throw new MinioPlusException(MinioPlusErrorCode.FILE_EXIST_FAILED.getCode(),fileKey+MinioPlusErrorCode.FILE_EXIST_FAILED.getMessage());
|
throw new MinioPlusException(MinioPlusErrorCode.FILE_EXIST_FAILED.getCode(), fileKey + MinioPlusErrorCode.FILE_EXIST_FAILED.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Boolean.TRUE.equals(metadata.getIsFinished())){
|
if (Boolean.TRUE.equals(metadata.getIsFinished())) {
|
||||||
// 如果文件已上传完成,直接返回true,不进行合并
|
// 如果文件已上传完成,直接返回true,不进行合并
|
||||||
completeResultVo.setIsComplete(true);
|
completeResultVo.setIsComplete(true);
|
||||||
return completeResultVo;
|
return completeResultVo;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(metadata.getStorageBucket().equals(StorageBucketEnums.IMAGE.getCode())){
|
if (metadata.getStorageBucket().equals(StorageBucketEnums.IMAGE.getCode())) {
|
||||||
// 图片时,生成图片的上传链接
|
// 图片时,生成图片的上传链接
|
||||||
List<FileCheckResultVo.Part> partList = new ArrayList<>();
|
List<FileCheckResultVo.Part> partList = new ArrayList<>();
|
||||||
|
|
||||||
FileCheckResultVo.Part part = new FileCheckResultVo.Part();
|
FileCheckResultVo.Part part = new FileCheckResultVo.Part();
|
||||||
part.setUploadId(metadata.getFileKey());
|
part.setUploadId(metadata.getFileKey());
|
||||||
part.setUrl("/storage/upload/image/"+metadata.getFileKey());
|
part.setUrl("/storage/upload/image/" + metadata.getFileKey());
|
||||||
part.setStartPosition(0L);
|
part.setStartPosition(0L);
|
||||||
part.setEndPosition(metadata.getFileSize());
|
part.setEndPosition(metadata.getFileSize());
|
||||||
partList.add(part);
|
partList.add(part);
|
||||||
@ -316,7 +315,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
searchDto.setFileMd5(metadata.getFileMd5());
|
searchDto.setFileMd5(metadata.getFileMd5());
|
||||||
searchDto.setIsFinished(false);
|
searchDto.setIsFinished(false);
|
||||||
List<FileMetadataInfoVo> others = metadataRepository.list(searchDto);
|
List<FileMetadataInfoVo> others = metadataRepository.list(searchDto);
|
||||||
if(CollUtil.isNotEmpty(others)){
|
if (CollUtil.isNotEmpty(others)) {
|
||||||
for (FileMetadataInfoVo other : others) {
|
for (FileMetadataInfoVo other : others) {
|
||||||
updateDTO = new FileMetadataInfoUpdateDTO();
|
updateDTO = new FileMetadataInfoUpdateDTO();
|
||||||
updateDTO.setId(other.getId());
|
updateDTO.setId(other.getId());
|
||||||
@ -325,8 +324,8 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
metadataRepository.update(updateDTO);
|
metadataRepository.update(updateDTO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
if(!metadata.getUploadTaskId().equals(completeResultVo.getUploadTaskId())){
|
if (!metadata.getUploadTaskId().equals(completeResultVo.getUploadTaskId())) {
|
||||||
FileMetadataInfoUpdateDTO updateDTO = new FileMetadataInfoUpdateDTO();
|
FileMetadataInfoUpdateDTO updateDTO = new FileMetadataInfoUpdateDTO();
|
||||||
updateDTO.setId(metadata.getId());
|
updateDTO.setId(metadata.getId());
|
||||||
updateDTO.setUploadTaskId(completeResultVo.getUploadTaskId());
|
updateDTO.setUploadTaskId(completeResultVo.getUploadTaskId());
|
||||||
@ -354,7 +353,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
saveDto.setFileMimeType(metadata.getFileMimeType());
|
saveDto.setFileMimeType(metadata.getFileMimeType());
|
||||||
saveDto.setIsPreview(metadata.getIsPreview());
|
saveDto.setIsPreview(metadata.getIsPreview());
|
||||||
|
|
||||||
Boolean isCreateFile = createFile(saveDto,file);
|
Boolean isCreateFile = createFile(saveDto, file);
|
||||||
|
|
||||||
FileMetadataInfoUpdateDTO updateDTO = new FileMetadataInfoUpdateDTO();
|
FileMetadataInfoUpdateDTO updateDTO = new FileMetadataInfoUpdateDTO();
|
||||||
updateDTO.setId(metadata.getId());
|
updateDTO.setId(metadata.getId());
|
||||||
@ -364,8 +363,8 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
|
|
||||||
return isCreateFile;
|
return isCreateFile;
|
||||||
|
|
||||||
}catch(Exception e){
|
} catch (Exception e) {
|
||||||
log.error(MinioPlusErrorCode.FILE_UPLOAD_FAILED.getMessage(),e);
|
log.error(MinioPlusErrorCode.FILE_UPLOAD_FAILED.getMessage(), e);
|
||||||
throw new MinioPlusException(MinioPlusErrorCode.FILE_UPLOAD_FAILED);
|
throw new MinioPlusException(MinioPlusErrorCode.FILE_UPLOAD_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,14 +375,14 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
|
|
||||||
FileMetadataInfoVo metadata = getFileMetadataInfo(fileKey, userId);
|
FileMetadataInfoVo metadata = getFileMetadataInfo(fileKey, userId);
|
||||||
|
|
||||||
try{
|
try {
|
||||||
// 文件权限校验,元数据为空或者当前登录用户不是文件所有者时抛出异常
|
// 文件权限校验,元数据为空或者当前登录用户不是文件所有者时抛出异常
|
||||||
this.authentication(metadata, fileKey, userId);
|
this.authentication(metadata, fileKey, userId);
|
||||||
|
|
||||||
return minioS3Client.getDownloadUrl(metadata.getFileName(),metadata.getFileMimeType(),metadata.getStorageBucket(),metadata.getStoragePath() + "/"+ metadata.getFileMd5());
|
return minioS3Client.getDownloadUrl(metadata.getFileName(), metadata.getFileMimeType(), metadata.getStorageBucket(), metadata.getStoragePath() + "/" + metadata.getFileMd5());
|
||||||
}catch(Exception e){
|
} catch (Exception e) {
|
||||||
// 打印日志
|
// 打印日志
|
||||||
log.error(e.getMessage(),e);
|
log.error(e.getMessage(), e);
|
||||||
// 任何异常,统一返回给前端文件不存在
|
// 任何异常,统一返回给前端文件不存在
|
||||||
throw new MinioPlusException(MinioPlusErrorCode.FILE_EXIST_FAILED);
|
throw new MinioPlusException(MinioPlusErrorCode.FILE_EXIST_FAILED);
|
||||||
}
|
}
|
||||||
@ -394,15 +393,15 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
|
|
||||||
FileMetadataInfoVo metadata = getFileMetadataInfo(fileKey, userId);
|
FileMetadataInfoVo metadata = getFileMetadataInfo(fileKey, userId);
|
||||||
|
|
||||||
try{
|
try {
|
||||||
// 文件权限校验,元数据为空或者当前登录用户不是文件所有者时抛出异常
|
// 文件权限校验,元数据为空或者当前登录用户不是文件所有者时抛出异常
|
||||||
this.authentication(metadata, fileKey, userId);
|
this.authentication(metadata, fileKey, userId);
|
||||||
|
|
||||||
return minioS3Client.getPreviewUrl(metadata.getFileMimeType(),metadata.getStorageBucket(),metadata.getStoragePath() + "/"+ metadata.getFileMd5());
|
return minioS3Client.getPreviewUrl(metadata.getFileMimeType(), metadata.getStorageBucket(), metadata.getStoragePath() + "/" + metadata.getFileMd5());
|
||||||
|
|
||||||
}catch(Exception e){
|
} catch (Exception e) {
|
||||||
// 打印日志
|
// 打印日志
|
||||||
log.error(e.getMessage(),e);
|
log.error(e.getMessage(), e);
|
||||||
// 任何异常,统一返回给前端文件不存在
|
// 任何异常,统一返回给前端文件不存在
|
||||||
throw new MinioPlusException(MinioPlusErrorCode.FILE_EXIST_FAILED);
|
throw new MinioPlusException(MinioPlusErrorCode.FILE_EXIST_FAILED);
|
||||||
}
|
}
|
||||||
@ -413,48 +412,60 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
|
|
||||||
FileMetadataInfoVo metadata = getFileMetadataInfo(fileKey, userId);
|
FileMetadataInfoVo metadata = getFileMetadataInfo(fileKey, userId);
|
||||||
|
|
||||||
try{
|
try {
|
||||||
// 文件权限校验,元数据为空或者当前登录用户不是文件所有者时抛出异常
|
// 文件权限校验,元数据为空或者当前登录用户不是文件所有者时抛出异常
|
||||||
this.authentication(metadata, fileKey, userId);
|
this.authentication(metadata, fileKey, userId);
|
||||||
// 判断是否存在缩略图,设置桶名称
|
// 生成缩略图
|
||||||
String bucketName = Boolean.TRUE.equals(metadata.getIsPreview()) ? StorageBucketEnums.IMAGE_PREVIEW.getCode() : metadata.getStorageBucket();
|
String bucketName = generatePreviewImage(metadata);
|
||||||
// 创建图片预览地址
|
// 创建图片预览地址
|
||||||
return minioS3Client.getPreviewUrl(metadata.getFileMimeType(),bucketName,metadata.getStoragePath() + "/"+ metadata.getFileMd5());
|
return minioS3Client.getPreviewUrl(metadata.getFileMimeType(), bucketName, metadata.getStoragePath() + "/" + metadata.getFileMd5());
|
||||||
|
} catch (Exception e) {
|
||||||
}catch(Exception e){
|
|
||||||
// 打印日志
|
// 打印日志
|
||||||
log.error(e.getMessage(),e);
|
log.error(e.getMessage(), e);
|
||||||
// 任何异常,统一返回给前端文件不存在
|
// 任何异常,统一返回给前端文件不存在
|
||||||
throw new MinioPlusException(MinioPlusErrorCode.FILE_EXIST_FAILED);
|
throw new MinioPlusException(MinioPlusErrorCode.FILE_EXIST_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件元数据
|
||||||
|
*
|
||||||
|
* @param metadata 文件元数据
|
||||||
|
* @return 缩略图桶路径
|
||||||
|
* @author <a href="mailto:tianxiang.deng@foxmail.com">BaldHead</a>
|
||||||
|
* @since 2024-06-14 14:44:52
|
||||||
|
*/
|
||||||
|
private String generatePreviewImage(FileMetadataInfoVo metadata) {
|
||||||
|
try {
|
||||||
|
if (Boolean.FALSE.equals(metadata.getIsPreview())) {
|
||||||
|
// 获取原图的bytes
|
||||||
|
byte[] imageOriginBytes = minioS3Client.getObject(StorageBucketEnums.IMAGE.getCode(), metadata.getStoragePath() + "/" + metadata.getFileMd5());
|
||||||
|
// 压缩缩略图
|
||||||
|
ByteArrayOutputStream largeImage = CommonUtil.resizeImage(new ByteArrayInputStream(imageOriginBytes), properties.getThumbnail().getSize());
|
||||||
|
byte[] largeImageBytes = largeImage.toByteArray();
|
||||||
|
minioS3Client.putObject(StorageBucketEnums.IMAGE_PREVIEW.getCode(), CommonUtil.getObjectName(metadata.getFileMd5()), new ByteArrayInputStream(largeImageBytes), largeImageBytes.length, metadata.getFileMimeType());
|
||||||
|
return StorageBucketEnums.IMAGE_PREVIEW.getCode();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 打印日志
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
// 任何异常,统一返回给前端文件不存在
|
||||||
|
throw new MinioPlusException(MinioPlusErrorCode.FILE_EXIST_FAILED);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean createFile(FileMetadataInfoSaveDTO saveDTO, byte[] fileBytes) {
|
public Boolean createFile(FileMetadataInfoSaveDTO saveDTO, byte[] fileBytes) {
|
||||||
|
|
||||||
// 写入文件
|
// 写入文件
|
||||||
minioS3Client.putObject(saveDTO.getStorageBucket(), CommonUtil.getObjectName(saveDTO.getFileMd5()), new ByteArrayInputStream(fileBytes), saveDTO.getFileSize(), saveDTO.getFileMimeType());
|
minioS3Client.putObject(saveDTO.getStorageBucket(), CommonUtil.getObjectName(saveDTO.getFileMd5()), new ByteArrayInputStream(fileBytes), saveDTO.getFileSize(), saveDTO.getFileMimeType());
|
||||||
|
|
||||||
// 判断是否生成缩略图
|
|
||||||
if(Boolean.TRUE.equals(saveDTO.getIsPreview())){
|
|
||||||
|
|
||||||
try{
|
|
||||||
ByteArrayOutputStream largeImage = CommonUtil.resizeImage(new ByteArrayInputStream(fileBytes), properties.getThumbnail().getSize());
|
|
||||||
byte[] largeImageBytes = largeImage.toByteArray();
|
|
||||||
minioS3Client.putObject(StorageBucketEnums.IMAGE_PREVIEW.getCode(), CommonUtil.getObjectName(saveDTO.getFileMd5()), new ByteArrayInputStream(largeImageBytes), largeImageBytes.length, saveDTO.getFileMimeType());
|
|
||||||
}catch(Exception e){
|
|
||||||
log.error(MinioPlusErrorCode.FILE_PREVIEW_WRITE_FAILED.getMessage(),e);
|
|
||||||
throw new MinioPlusException(MinioPlusErrorCode.FILE_PREVIEW_WRITE_FAILED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<FileMetadataInfoVo,byte[]> read(String fileKey) {
|
public Pair<FileMetadataInfoVo, byte[]> read(String fileKey) {
|
||||||
|
|
||||||
// 查询文件元数据
|
// 查询文件元数据
|
||||||
FileMetadataInfoDTO fileMetadataInfo = new FileMetadataInfoDTO();
|
FileMetadataInfoDTO fileMetadataInfo = new FileMetadataInfoDTO();
|
||||||
@ -466,9 +477,9 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 读取流
|
// 读取流
|
||||||
byte[] fileBytes = minioS3Client.getObject(fileMetadataInfoVo.getStorageBucket(), fileMetadataInfoVo.getStoragePath() + "/" + fileMetadataInfoVo.getFileMd5());
|
byte[] fileBytes = minioS3Client.getObject(fileMetadataInfoVo.getStorageBucket(), fileMetadataInfoVo.getStoragePath() + "/" + fileMetadataInfoVo.getFileMd5());
|
||||||
|
|
||||||
return Pair.of(fileMetadataInfoVo,fileBytes);
|
return Pair.of(fileMetadataInfoVo, fileBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -501,7 +512,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void remove(FileMetadataInfoVo metadata){
|
private void remove(FileMetadataInfoVo metadata) {
|
||||||
// 删除元数据信息
|
// 删除元数据信息
|
||||||
metadataRepository.remove(metadata.getId());
|
metadataRepository.remove(metadata.getId());
|
||||||
|
|
||||||
@ -509,12 +520,12 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
fileMetadataInfo.setFileMd5(metadata.getFileMd5());
|
fileMetadataInfo.setFileMd5(metadata.getFileMd5());
|
||||||
List<FileMetadataInfoVo> metadataList = metadataRepository.list(fileMetadataInfo);
|
List<FileMetadataInfoVo> metadataList = metadataRepository.list(fileMetadataInfo);
|
||||||
|
|
||||||
if(CollUtil.isEmpty(metadataList)){
|
if (CollUtil.isEmpty(metadataList)) {
|
||||||
// 当不存在任何该MD5值的文件元数据时,删除物理文件
|
// 当不存在任何该MD5值的文件元数据时,删除物理文件
|
||||||
minioS3Client.removeObject(metadata.getStorageBucket(), metadata.getStoragePath() + "/" + metadata.getFileMd5());
|
minioS3Client.removeObject(metadata.getStorageBucket(), metadata.getStoragePath() + "/" + metadata.getFileMd5());
|
||||||
if(Boolean.TRUE.equals(metadata.getIsPreview())){
|
if (Boolean.TRUE.equals(metadata.getIsPreview())) {
|
||||||
// 当存在缩略图时,同步删除缩略图
|
// 当存在缩略图时,同步删除缩略图
|
||||||
minioS3Client.removeObject(StorageBucketEnums.IMAGE_PREVIEW.getCode(), metadata.getStoragePath() + "/" + metadata.getFileMd5());
|
minioS3Client.removeObject(StorageBucketEnums.IMAGE_PREVIEW.getCode(), metadata.getStoragePath() + "/" + metadata.getFileMd5());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -522,6 +533,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
/**
|
/**
|
||||||
* 根据用户取得文件元数据信息
|
* 根据用户取得文件元数据信息
|
||||||
* 当userId匹配时直接返回,不匹配时检查是否存在公有元数据
|
* 当userId匹配时直接返回,不匹配时检查是否存在公有元数据
|
||||||
|
*
|
||||||
* @param fileKey 文件KEY
|
* @param fileKey 文件KEY
|
||||||
* @param userId 用户主键
|
* @param userId 用户主键
|
||||||
* @return 文件元数据信息
|
* @return 文件元数据信息
|
||||||
@ -547,17 +559,17 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
* 文件为私有文件且当前登录用户不是文件所有者时抛出异常
|
* 文件为私有文件且当前登录用户不是文件所有者时抛出异常
|
||||||
*
|
*
|
||||||
* @param metadata 文件元数据
|
* @param metadata 文件元数据
|
||||||
* @param fileKey 文件key
|
* @param fileKey 文件key
|
||||||
* @param userId 用户主键
|
* @param userId 用户主键
|
||||||
*/
|
*/
|
||||||
private void authentication(FileMetadataInfoVo metadata, String fileKey, String userId){
|
private void authentication(FileMetadataInfoVo metadata, String fileKey, String userId) {
|
||||||
if (null == metadata) {
|
if (null == metadata) {
|
||||||
throw new MinioPlusException(MinioPlusErrorCode.FILE_EXIST_FAILED.getCode(), fileKey + MinioPlusErrorCode.FILE_EXIST_FAILED.getMessage());
|
throw new MinioPlusException(MinioPlusErrorCode.FILE_EXIST_FAILED.getCode(), fileKey + MinioPlusErrorCode.FILE_EXIST_FAILED.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 元数据信息存在,判断权限
|
// 元数据信息存在,判断权限
|
||||||
if(Boolean.TRUE.equals(metadata.getIsPrivate()) && !userId.equals(metadata.getCreateUser())){
|
if (Boolean.TRUE.equals(metadata.getIsPrivate()) && !userId.equals(metadata.getCreateUser())) {
|
||||||
throw new MinioPlusException(MinioPlusErrorCode.FILE_PERMISSION_CHECK_FAILED.getCode(), fileKey + "用户"+userId+MinioPlusErrorCode.FILE_PERMISSION_CHECK_FAILED.getMessage());
|
throw new MinioPlusException(MinioPlusErrorCode.FILE_PERMISSION_CHECK_FAILED.getCode(), fileKey + "用户" + userId + MinioPlusErrorCode.FILE_PERMISSION_CHECK_FAILED.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -580,16 +592,16 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
*
|
*
|
||||||
* @param bucketName 桶名称
|
* @param bucketName 桶名称
|
||||||
* @param objectName 对象名称(含路径)
|
* @param objectName 对象名称(含路径)
|
||||||
* @param uploadId 上传任务编号
|
* @param uploadId 上传任务编号
|
||||||
* @param fileSize 文件大小
|
* @param fileSize 文件大小
|
||||||
* @param start 开始位置
|
* @param start 开始位置
|
||||||
* @param partNumber 块号
|
* @param partNumber 块号
|
||||||
* @return {@link FileCheckResultVo.Part}
|
* @return {@link FileCheckResultVo.Part}
|
||||||
*/
|
*/
|
||||||
private FileCheckResultVo.Part buildResultPart(String bucketName,String objectName,String uploadId, Long fileSize, long start, Integer partNumber) {
|
private FileCheckResultVo.Part buildResultPart(String bucketName, String objectName, String uploadId, Long fileSize, long start, Integer partNumber) {
|
||||||
// 计算起始位置
|
// 计算起始位置
|
||||||
long end = Math.min(start + properties.getPart().getSize(), fileSize);
|
long end = Math.min(start + properties.getPart().getSize(), fileSize);
|
||||||
String uploadUrl = minioS3Client.getUploadObjectUrl(bucketName, objectName, uploadId,String.valueOf(partNumber));
|
String uploadUrl = minioS3Client.getUploadObjectUrl(bucketName, objectName, uploadId, String.valueOf(partNumber));
|
||||||
FileCheckResultVo.Part part = new FileCheckResultVo.Part();
|
FileCheckResultVo.Part part = new FileCheckResultVo.Part();
|
||||||
part.setUploadId(uploadId);
|
part.setUploadId(uploadId);
|
||||||
// 上传地址
|
// 上传地址
|
||||||
@ -603,6 +615,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 断点续传-创建断点的URL
|
* 断点续传-创建断点的URL
|
||||||
|
*
|
||||||
* @param fileMetadataVo 文件元数据信息
|
* @param fileMetadataVo 文件元数据信息
|
||||||
* @return CreateUploadUrlRespBO 分片结果
|
* @return CreateUploadUrlRespBO 分片结果
|
||||||
*/
|
*/
|
||||||
@ -644,7 +657,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
// 丢失的块号-断点续传时必传
|
// 丢失的块号-断点续传时必传
|
||||||
bo.setMissPartNum(missingNumbers);
|
bo.setMissPartNum(missingNumbers);
|
||||||
|
|
||||||
if(missingNumbers.size() != chunkNum){
|
if (missingNumbers.size() != chunkNum) {
|
||||||
// 任务id,任务id可能会失效
|
// 任务id,任务id可能会失效
|
||||||
bo.setUploadId(fileMetadataVo.getUploadTaskId());
|
bo.setUploadId(fileMetadataVo.getUploadTaskId());
|
||||||
}
|
}
|
||||||
@ -665,8 +678,9 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 合并分片
|
* 合并分片
|
||||||
|
*
|
||||||
* @param metadataInfo 文件元数据信息
|
* @param metadataInfo 文件元数据信息
|
||||||
* @param partMd5List 分片集合
|
* @param partMd5List 分片集合
|
||||||
* @return 合并结果
|
* @return 合并结果
|
||||||
*/
|
*/
|
||||||
public CompleteResultVo completeMultipartUpload(FileMetadataInfoVo metadataInfo, List<String> partMd5List) {
|
public CompleteResultVo completeMultipartUpload(FileMetadataInfoVo metadataInfo, List<String> partMd5List) {
|
||||||
@ -676,12 +690,12 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
// 获取所有的分片信息
|
// 获取所有的分片信息
|
||||||
ListParts listParts = this.buildResultPart(metadataInfo);
|
ListParts listParts = this.buildResultPart(metadataInfo);
|
||||||
|
|
||||||
List<Integer> missingNumbers =new ArrayList<>();
|
List<Integer> missingNumbers = new ArrayList<>();
|
||||||
|
|
||||||
// 分块数量
|
// 分块数量
|
||||||
Integer chunkNum = metadataInfo.getPartNumber();
|
Integer chunkNum = metadataInfo.getPartNumber();
|
||||||
|
|
||||||
if(partMd5List==null || chunkNum != partMd5List.size()){
|
if (partMd5List == null || chunkNum != partMd5List.size()) {
|
||||||
throw new MinioPlusException(MinioPlusErrorCode.FILE_PART_NUM_CHECK_FAILED);
|
throw new MinioPlusException(MinioPlusErrorCode.FILE_PART_NUM_CHECK_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -689,16 +703,16 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
for (int i = 1; i <= chunkNum; i++) {
|
for (int i = 1; i <= chunkNum; i++) {
|
||||||
boolean findPart = false;
|
boolean findPart = false;
|
||||||
for (ListParts.Part part : listParts.getPartList()) {
|
for (ListParts.Part part : listParts.getPartList()) {
|
||||||
if(part.getPartNumber() == i && CharSequenceUtil.equalsIgnoreCase(part.getEtag(), partMd5List.get(i - 1))){
|
if (part.getPartNumber() == i && CharSequenceUtil.equalsIgnoreCase(part.getEtag(), partMd5List.get(i - 1))) {
|
||||||
findPart = true;
|
findPart = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!findPart){
|
if (!findPart) {
|
||||||
missingNumbers.add(i);
|
missingNumbers.add(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(CollUtil.isNotEmpty(missingNumbers)){
|
if (CollUtil.isNotEmpty(missingNumbers)) {
|
||||||
CreateUploadUrlReqBO bo = new CreateUploadUrlReqBO();
|
CreateUploadUrlReqBO bo = new CreateUploadUrlReqBO();
|
||||||
// 文件md5
|
// 文件md5
|
||||||
bo.setFileMd5(metadataInfo.getFileMd5());
|
bo.setFileMd5(metadataInfo.getFileMd5());
|
||||||
@ -710,7 +724,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
bo.setIsSequel(Boolean.TRUE);
|
bo.setIsSequel(Boolean.TRUE);
|
||||||
// 丢失的块号-断点续传时必传
|
// 丢失的块号-断点续传时必传
|
||||||
bo.setMissPartNum(missingNumbers);
|
bo.setMissPartNum(missingNumbers);
|
||||||
if(missingNumbers.size() != chunkNum){
|
if (missingNumbers.size() != chunkNum) {
|
||||||
// 任务id,任务id可能会失效
|
// 任务id,任务id可能会失效
|
||||||
bo.setUploadId(metadataInfo.getUploadTaskId());
|
bo.setUploadId(metadataInfo.getUploadTaskId());
|
||||||
}
|
}
|
||||||
@ -725,12 +739,12 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
completeResultVo.setIsComplete(false);
|
completeResultVo.setIsComplete(false);
|
||||||
completeResultVo.setUploadTaskId(createUploadUrlRespBO.getUploadTaskId());
|
completeResultVo.setUploadTaskId(createUploadUrlRespBO.getUploadTaskId());
|
||||||
completeResultVo.setPartList(createUploadUrlRespBO.getParts());
|
completeResultVo.setPartList(createUploadUrlRespBO.getParts());
|
||||||
}else{
|
} else {
|
||||||
// 合并分块
|
// 合并分块
|
||||||
boolean writeResponse = minioS3Client.completeMultipartUpload(metadataInfo.getStorageBucket()
|
boolean writeResponse = minioS3Client.completeMultipartUpload(metadataInfo.getStorageBucket()
|
||||||
,listParts.getObjectName()
|
, listParts.getObjectName()
|
||||||
,metadataInfo.getUploadTaskId()
|
, metadataInfo.getUploadTaskId()
|
||||||
,listParts.getPartList()
|
, listParts.getPartList()
|
||||||
);
|
);
|
||||||
completeResultVo.setIsComplete(writeResponse);
|
completeResultVo.setIsComplete(writeResponse);
|
||||||
completeResultVo.setPartList(new ArrayList<>());
|
completeResultVo.setPartList(new ArrayList<>());
|
||||||
@ -745,7 +759,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
* @param metadataInfo 文件元数据信息
|
* @param metadataInfo 文件元数据信息
|
||||||
* @return {@link ListParts} 分片任务信息
|
* @return {@link ListParts} 分片任务信息
|
||||||
*/
|
*/
|
||||||
private ListParts buildResultPart(FileMetadataInfoVo metadataInfo){
|
private ListParts buildResultPart(FileMetadataInfoVo metadataInfo) {
|
||||||
String objectName = CommonUtil.getObjectName(metadataInfo.getFileMd5());
|
String objectName = CommonUtil.getObjectName(metadataInfo.getFileMd5());
|
||||||
// 获取所有的分片信息
|
// 获取所有的分片信息
|
||||||
return minioS3Client.listParts(metadataInfo.getStorageBucket(), objectName, metadataInfo.getPartNumber(), metadataInfo.getUploadTaskId());
|
return minioS3Client.listParts(metadataInfo.getStorageBucket(), objectName, metadataInfo.getPartNumber(), metadataInfo.getUploadTaskId());
|
||||||
@ -777,7 +791,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
// 开始位置
|
// 开始位置
|
||||||
long start = (long) (bo.getMissPartNum().get(0) - 1) * properties.getPart().getSize();
|
long start = (long) (bo.getMissPartNum().get(0) - 1) * properties.getPart().getSize();
|
||||||
for (int partNumber : bo.getMissPartNum()) {
|
for (int partNumber : bo.getMissPartNum()) {
|
||||||
FileCheckResultVo.Part part = this.buildResultPart(bucketName,storagePath, uploadId, bo.getFileSize(), start, partNumber);
|
FileCheckResultVo.Part part = this.buildResultPart(bucketName, storagePath, uploadId, bo.getFileSize(), start, partNumber);
|
||||||
// 更改下一次的开始位置
|
// 更改下一次的开始位置
|
||||||
start = start + properties.getPart().getSize();
|
start = start + properties.getPart().getSize();
|
||||||
partList.add(part);
|
partList.add(part);
|
||||||
@ -803,7 +817,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
FileCheckResultVo.Part part = new FileCheckResultVo.Part();
|
FileCheckResultVo.Part part = new FileCheckResultVo.Part();
|
||||||
// 图片上传时,直接使用fileKey作为uploadId
|
// 图片上传时,直接使用fileKey作为uploadId
|
||||||
part.setUploadId(fileKey);
|
part.setUploadId(fileKey);
|
||||||
part.setUrl("/storage/upload/image/"+fileKey);
|
part.setUrl("/storage/upload/image/" + fileKey);
|
||||||
part.setStartPosition(0L);
|
part.setStartPosition(0L);
|
||||||
part.setEndPosition(bo.getFileSize());
|
part.setEndPosition(bo.getFileSize());
|
||||||
partList.add(part);
|
partList.add(part);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user