【EasyPan】项目常见问题解答(自用&持续更新中…)汇总版
recoverFileBatch
方法实现将回收站中的文件/文件夹批量还原到根目录的业务逻辑,主要特点:
@Transactional
确保操作原子性// 输入参数处理
String[] fileIdArray = fileIds.split(",");
// 构建回收站文件查询条件
FileInfoQuery query = new FileInfoQuery();
query.setUserId(userId); // 用户隔离
query.setFileIdArray(fileIdArray); // 目标文件ID集合
query.setDelFlag(FileDelFlagEnums.RECYCLE.getFlag()); // del_flag=2
安全设计:
// 收集待处理的子文件夹ID
List<String> delFileSubFolderFileIdList = new ArrayList<>();
// 递归查找DEL状态的子内容
findAllSubFolderFileList(delFileSubFolderFileIdList, userId,
fileInfo.getFileId(), FileDelFlagEnums.DEL.getFlag());
递归特点:
// 查询根目录下的正常文件
query = new FileInfoQuery();
query.setUserId(userId);
query.setDelFlag(FileDelFlagEnums.USING.getFlag()); // del_flag=0
query.setFilePid(Constants.ZERO_STR); // file_pid=0
// 转换为文件名映射表
Map<String, FileInfo> rootFileMap = allRootFileList.stream()
.collect(Collectors.toMap(FileInfo::getFileName,
Function.identity(), (data1, data2) -> data2));
优化点:
FileInfo fileInfo = new FileInfo();
fileInfo.setDelFlag(FileDelFlagEnums.USING.getFlag()); // DEL→USING
fileInfoMapper.updateFileDelFlagBatch(fileInfo, userId,
delFileSubFolderFileIdList, null, FileDelFlagEnums.DEL.getFlag());
FileInfo fileInfo = new FileInfo();
fileInfo.setDelFlag(FileDelFlagEnums.USING.getFlag()); // RECYCLE→USING
fileInfo.setFilePid(Constants.ZERO_STR); // 重置到根目录
fileInfo.setLastUpdateTime(new Date()); // 更新时间
fileInfoMapper.updateFileDelFlagBatch(fileInfo, userId,
null, delFileIdList, FileDelFlagEnums.RECYCLE.getFlag());
// 检查根目录同名文件
FileInfo rootFileInfo = rootFileMap.get(item.getFileName());
if (rootFileInfo != null) {
String fileName = StringTools.rename(item.getFileName()); // 自动重命名
FileInfo updateInfo = new FileInfo();
updateInfo.setFileName(fileName);
fileInfoMapper.updateByFileIdAndUserId(updateInfo,
item.getFileId(), userId);
}
SELECT * FROM file_info
WHERE user_id = 'user123'
AND file_id IN ('file1','file2')
AND del_flag = 2
UPDATE file_info SET
del_flag = 0
WHERE user_id = 'user123'
AND file_pid IN ('folder1','folder2')
AND del_flag = 1
UPDATE file_info SET
del_flag = 0,
file_pid = '0',
last_update_time = NOW()
WHERE user_id = 'user123'
AND file_id IN ('file1','file2')
AND del_flag = 2
/**
* 批量从回收站恢复文件/文件夹
* @param userId 用户ID
* @param fileIds 要恢复的文件ID列表,多个用逗号分隔
*/
@Override
@Transactional(rollbackFor = Exception.class) // 声明式事务管理,任何异常都会回滚
public void recoverFileBatch(String userId, String fileIds) {
// 1. 参数预处理:将逗号分隔的字符串转为数组
String[] fileIdArray = fileIds.split(",");
// 2. 构建查询条件:查询用户选中的回收站文件
FileInfoQuery query = new FileInfoQuery();
query.setUserId(userId); // 用户隔离
query.setFileIdArray(fileIdArray); // 目标文件ID集合
query.setDelFlag(FileDelFlagEnums.RECYCLE.getFlag()); // 只查询回收站状态的文件(del_flag=2)
// 3. 执行查询获取待恢复文件列表
List<FileInfo> fileInfoList = this.fileInfoMapper.selectList(query);
// 4. 递归查找所有需要恢复的子文件夹(深度优先遍历)
List<String> delFileSubFolderFileIdList = new ArrayList<>(); // 存储所有子文件夹ID
for (FileInfo fileInfo : fileInfoList) {
// 只处理文件夹类型(文件不需要递归)
if (FileFolderTypeEnums.FOLDER.getType().equals(fileInfo.getFolderType())) {
findAllSubFolderFileList(delFileSubFolderFileIdList, userId,
fileInfo.getFileId(), FileDelFlagEnums.DEL.getFlag());
}
}
// 5. 查询根目录现有文件(用于文件名冲突检测)
query = new FileInfoQuery();
query.setUserId(userId);
query.setDelFlag(FileDelFlagEnums.USING.getFlag()); // 正常状态文件(del_flag=0)
query.setFilePid(Constants.ZERO_STR); // 根目录文件(file_pid=0)
List<FileInfo> allRootFileList = this.findListByParam(query);
// 6. 构建文件名映射表(快速冲突检测)
Map<String, FileInfo> rootFileMap = allRootFileList.stream()
.collect(Collectors.toMap(
FileInfo::getFileName,
Function.identity(),
(existing, replacement) -> replacement)); // 同名文件保留后者
// 7. 批量恢复子文件状态(DEL→USING)
if (!delFileSubFolderFileIdList.isEmpty()) {
FileInfo fileInfo = new FileInfo();
fileInfo.setDelFlag(FileDelFlagEnums.USING.getFlag()); // 设置为正常状态
this.fileInfoMapper.updateFileDelFlagBatch(
fileInfo,
userId,
delFileSubFolderFileIdList, // 基于子文件夹ID的条件
null,
FileDelFlagEnums.DEL.getFlag()); // 只更新DEL状态的文件
}
// 8. 批量恢复主文件状态(RECYCLE→USING)并移动到根目录
List<String> delFileIdList = Arrays.asList(fileIdArray); // 用户原始选择的文件ID
FileInfo fileInfo = new FileInfo();
fileInfo.setDelFlag(FileDelFlagEnums.USING.getFlag()); // 设置为正常状态
fileInfo.setFilePid(Constants.ZERO_STR); // 重置到根目录
fileInfo.setLastUpdateTime(new Date()); // 更新操作时间
this.fileInfoMapper.updateFileDelFlagBatch(
fileInfo,
userId,
null,
delFileIdList, // 基于自身ID的条件
FileDelFlagEnums.RECYCLE.getFlag()); // 只更新RECYCLE状态的文件
// 9. 处理文件名冲突(自动重命名)
for (FileInfo item : fileInfoList) {
FileInfo rootFileInfo = rootFileMap.get(item.getFileName());
// 检测到同名文件时自动重命名
if (rootFileInfo != null) {
String fileName = StringTools.rename(item.getFileName()); // 生成新文件名
FileInfo updateInfo = new FileInfo();
updateInfo.setFileName(fileName);
this.fileInfoMapper.updateByFileIdAndUserId(
updateInfo,
item.getFileId(),
userId);
}
}
}