fix:优化文件删除回收站功能,支持批量设置过期时间
This commit is contained in:
@@ -4,10 +4,12 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Schema(description = "从回收站彻底删除请求")
|
||||
public class PermanentDeleteFromRecycleReq {
|
||||
@Schema(description = "要彻底删除的文件/目录ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "文件/目录ID不能为空")
|
||||
private Long id;
|
||||
@Schema(description = "要彻底删除的文件/目录ID列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "文件/目录ID列表不能为空")
|
||||
private List<Long> ids;
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Schema(description = "从回收站还原请求")
|
||||
public class RestoreFromRecycleReq {
|
||||
@Schema(description = "要还原的文件/目录ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "文件/目录ID不能为空")
|
||||
private Long id;
|
||||
@Schema(description = "要还原的文件/目录ID列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "文件/目录ID列表不能为空")
|
||||
private List<Long> ids;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.sdm.common.entity.req.data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Schema(description = "批量更新回收站过期时间请求")
|
||||
public class UpdateRecycleExpireReq {
|
||||
@Schema(description = "文件/目录ID列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "文件/目录ID列表不能为空")
|
||||
private List<Long> ids;
|
||||
|
||||
@Schema(description = "保留天数(从删除时间开始计算)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "保留天数不能为空")
|
||||
@Min(value = 0, message = "保留天数不能小于0")
|
||||
private Integer days;
|
||||
}
|
||||
@@ -146,31 +146,44 @@ public class DataFileController implements IDataFeignClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* 从回收站还原
|
||||
* 批量从回收站还原
|
||||
*
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
@SysLog("从回收站还原")
|
||||
@PostMapping("/restoreFromRecycle")
|
||||
@Operation(summary = "从回收站还原", description = "将文件/目录从回收站还原到原位置")
|
||||
@Operation(summary = "从回收站还原", description = "将文件/目录从回收站还原到原位置(支持批量)")
|
||||
public SdmResponse restoreFromRecycle(@RequestBody @Validated RestoreFromRecycleReq req) {
|
||||
return IDataFileService.restoreFromRecycle(req);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从回收站彻底删除
|
||||
* 批量从回收站彻底删除
|
||||
*
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
@SysLog("从回收站彻底删除")
|
||||
@PostMapping("/permanentDeleteFromRecycle")
|
||||
@Operation(summary = "从回收站彻底删除", description = "从回收站彻底删除文件/目录(物理删除,不可恢复)")
|
||||
@Operation(summary = "从回收站彻底删除", description = "从回收站彻底删除文件/目录(物理删除,不可恢复,支持批量)")
|
||||
public SdmResponse permanentDeleteFromRecycle(@RequestBody @Validated PermanentDeleteFromRecycleReq req) {
|
||||
return IDataFileService.permanentDeleteFromRecycle(req);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新回收站过期时间
|
||||
*
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
@SysLog("更新回收站过期时间")
|
||||
@PostMapping("/updateRecycleExpire")
|
||||
@Operation(summary = "更新回收站过期时间", description = "批量更新回收站中文件/目录的过期时间")
|
||||
public SdmResponse updateRecycleExpire(@RequestBody @Validated UpdateRecycleExpireReq req) {
|
||||
return IDataFileService.updateRecycleExpire(req);
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索文件
|
||||
*
|
||||
|
||||
@@ -140,25 +140,34 @@ public interface IDataFileService {
|
||||
* @param req 回收站列表查询请求参数
|
||||
* @return 回收站列表响应
|
||||
*/
|
||||
default SdmResponse listRecycleBin(com.sdm.common.entity.req.data.ListRecycleBinReq req) {
|
||||
default SdmResponse listRecycleBin(ListRecycleBinReq req) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从回收站还原文件/目录
|
||||
* 批量从回收站还原文件/目录
|
||||
* @param req 还原请求参数
|
||||
* @return 还原结果响应
|
||||
*/
|
||||
default SdmResponse restoreFromRecycle(com.sdm.common.entity.req.data.RestoreFromRecycleReq req) {
|
||||
default SdmResponse restoreFromRecycle(RestoreFromRecycleReq req) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从回收站彻底删除文件/目录
|
||||
* 批量从回收站彻底删除文件/目录
|
||||
* @param req 彻底删除请求参数
|
||||
* @return 删除结果响应
|
||||
*/
|
||||
default SdmResponse permanentDeleteFromRecycle(com.sdm.common.entity.req.data.PermanentDeleteFromRecycleReq req) {
|
||||
default SdmResponse permanentDeleteFromRecycle(PermanentDeleteFromRecycleReq req) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新回收站过期时间
|
||||
* @param req 更新过期时间请求参数
|
||||
* @return 更新结果响应
|
||||
*/
|
||||
default SdmResponse updateRecycleExpire(com.sdm.common.entity.req.data.UpdateRecycleExpireReq req) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -105,6 +105,10 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
|
||||
private static final String FLOWABLE_SIMULATION_BASEDIR = "/home/simulation/";
|
||||
|
||||
@Value("${data.recycle.retention-days:7}")
|
||||
|
||||
|
||||
|
||||
|
||||
private Integer recycleRetentionDays;
|
||||
|
||||
@Autowired
|
||||
@@ -4686,8 +4690,30 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public SdmResponse restoreFromRecycle(RestoreFromRecycleReq req) {
|
||||
if (ObjectUtils.isEmpty(req.getIds())) {
|
||||
return SdmResponse.failed("未选择要还原的文件");
|
||||
}
|
||||
|
||||
List<String> messages = new ArrayList<>();
|
||||
for (Long id : req.getIds()) {
|
||||
SdmResponse resp = restoreSingleFile(id);
|
||||
if (!resp.isSuccess()) {
|
||||
throw new RuntimeException("还原文件(ID:" + id + ")失败: " + resp.getMessage());
|
||||
}
|
||||
if (resp.getData() != null && !Objects.equals(resp.getData(), "还原成功")) {
|
||||
messages.add(resp.getData().toString());
|
||||
}
|
||||
}
|
||||
|
||||
if (!messages.isEmpty()) {
|
||||
return SdmResponse.success("还原成功,部分文件已重命名: " + String.join("; ", messages));
|
||||
}
|
||||
return SdmResponse.success("批量还原成功");
|
||||
}
|
||||
|
||||
private SdmResponse restoreSingleFile(Long id) {
|
||||
FileMetadataInfo metadata = fileMetadataInfoService.lambdaQuery()
|
||||
.eq(FileMetadataInfo::getId, req.getId())
|
||||
.eq(FileMetadataInfo::getId, id)
|
||||
.isNotNull(FileMetadataInfo::getDeletedAt)
|
||||
.one();
|
||||
|
||||
@@ -4778,7 +4804,7 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
|
||||
}
|
||||
|
||||
log.info("成功从回收站还原: id={}, oldKey={}, newKey={}, newName={}", metadata.getId(), oldKey, restoreKey, restoreName);
|
||||
return SdmResponse.success(Objects.equals(restoreName, originalName) ? "还原成功" : "还原成功,原路径已存在,已重命名为: " + restoreName);
|
||||
return SdmResponse.success(Objects.equals(restoreName, originalName) ? "还原成功" : "已重命名为: " + restoreName);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("还原失败", e);
|
||||
@@ -4789,8 +4815,22 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public SdmResponse permanentDeleteFromRecycle(PermanentDeleteFromRecycleReq req) {
|
||||
if (ObjectUtils.isEmpty(req.getIds())) {
|
||||
return SdmResponse.failed("未选择要删除的文件");
|
||||
}
|
||||
|
||||
for (Long id : req.getIds()) {
|
||||
SdmResponse resp = permanentDeleteSingleFile(id);
|
||||
if (!resp.isSuccess()) {
|
||||
throw new RuntimeException("删除文件(ID:" + id + ")失败: " + resp.getMessage());
|
||||
}
|
||||
}
|
||||
return SdmResponse.success("批量彻底删除成功");
|
||||
}
|
||||
|
||||
private SdmResponse permanentDeleteSingleFile(Long id) {
|
||||
FileMetadataInfo metadata = fileMetadataInfoService.lambdaQuery()
|
||||
.eq(FileMetadataInfo::getId, req.getId())
|
||||
.eq(FileMetadataInfo::getId, id)
|
||||
.isNotNull(FileMetadataInfo::getDeletedAt)
|
||||
.one();
|
||||
|
||||
@@ -4816,4 +4856,64 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public SdmResponse updateRecycleExpire(UpdateRecycleExpireReq req) {
|
||||
if (ObjectUtils.isEmpty(req.getIds())) {
|
||||
return SdmResponse.failed("未选择要更新的文件");
|
||||
}
|
||||
|
||||
List<FileMetadataInfo> metadataList = fileMetadataInfoService.listByIds(req.getIds());
|
||||
if (CollectionUtils.isEmpty(metadataList)) {
|
||||
return SdmResponse.failed("文件不存在");
|
||||
}
|
||||
|
||||
int successCount = 0;
|
||||
for (FileMetadataInfo metadata : metadataList) {
|
||||
// 仅处理已删除的文件
|
||||
if (metadata.getDeletedAt() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 计算新的过期时间:基于 deletedAt + days
|
||||
LocalDateTime newExpireAt = metadata.getDeletedAt().plusDays(req.getDays());
|
||||
|
||||
// 如果是目录,递归更新子项
|
||||
if (Objects.equals(DataTypeEnum.DIRECTORY.getValue(), metadata.getDataType())) {
|
||||
updateDirectoryRecycleExpire(metadata, newExpireAt);
|
||||
} else {
|
||||
// 单文件更新
|
||||
metadata.setRecycleExpireAt(newExpireAt);
|
||||
metadata.setUpdateTime(LocalDateTime.now());
|
||||
fileMetadataInfoService.updateById(metadata);
|
||||
}
|
||||
successCount++;
|
||||
}
|
||||
|
||||
return SdmResponse.success("成功更新 " + successCount + " 个文件的回收站过期时间");
|
||||
}
|
||||
|
||||
private void updateDirectoryRecycleExpire(FileMetadataInfo rootDir, LocalDateTime newExpireAt) {
|
||||
// 1. 更新目录本身
|
||||
rootDir.setRecycleExpireAt(newExpireAt);
|
||||
rootDir.setUpdateTime(LocalDateTime.now());
|
||||
fileMetadataInfoService.updateById(rootDir);
|
||||
|
||||
// 2. 批量更新子项(包括子目录和文件)
|
||||
// 只要是该目录下的(objectKey以目录key为前缀),且已删除的,都更新
|
||||
String dirKey = rootDir.getObjectKey();
|
||||
if (!dirKey.endsWith("/")) {
|
||||
dirKey += "/";
|
||||
}
|
||||
|
||||
// 使用 LambdaUpdateWrapper 批量更新,效率更高
|
||||
fileMetadataInfoService.lambdaUpdate()
|
||||
.likeRight(FileMetadataInfo::getObjectKey, dirKey) // objectKey like 'dirKey%'
|
||||
.eq(FileMetadataInfo::getBucketName, rootDir.getBucketName())
|
||||
.isNotNull(FileMetadataInfo::getDeletedAt) // 必须是已删除的
|
||||
.set(FileMetadataInfo::getRecycleExpireAt, newExpireAt)
|
||||
.set(FileMetadataInfo::getUpdateTime, LocalDateTime.now())
|
||||
.update();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user