【EasyPan】removeFile2RecycleBatch方法及递归操作解析
【EasyPan】项目常见问题解答(自用&持续更新中…)汇总版
文件批量转移到回收站方法解析
一、方法总述
removeFile2RecycleBatch
方法实现将用户选中的文件/目录及其子内容批量移入回收站的业务逻辑,主要特点:
- 递归处理:深度遍历文件夹层级结构
- 双重状态更新:区分直接删除和回收站保留
- 批量操作:基于文件ID集合的批量SQL执行
- 事务安全:依赖MyBatis事务管理保证一致性
二、方法流程及时序图
核心处理流程
三、方法模块化解析
1. 数据准备模块
// 输入参数处理
String[] fileIdArray = fileIds.split(","); // 构建基础查询条件
FileInfoQuery query = new FileInfoQuery();
query.setUserId(userId);
query.setFileIdArray(fileIdArray);
query.setDelFlag(FileDelFlagEnums.USING.getFlag()); // del_flag=0
关键设计:
- 使用逗号分隔符处理批量ID
- 严格限定用户权限(userId)
- 只操作正常状态的文件(del_flag=0)
2. 递归查找模块
private void findAllSubFolderFileList(List<String> fileIdList, String userId, String fileId, Integer delFlag) {// 递归终止条件:无子文件夹时自动结束// 递归过程:深度优先遍历文件夹树
}
处理逻辑:
- 将当前文件夹ID加入结果集
- 查询该文件夹下的所有子文件夹
- 对每个子文件夹递归执行相同操作
3. 状态更新模块
子文件删除操作
// 更新条件:
// - 文件PID在delFilePidList中
// - 当前del_flag=0
this.fileInfoMapper.updateFileDelFlagBatch(updateInfo, userId, delFilePidList, // 基于父ID的条件null, FileDelFlagEnums.USING.getFlag()
);
选中文件回收站操作
// 更新条件:
// - 文件ID在delFileIdList中
// - 当前del_flag=0
this.fileInfoMapper.updateFileDelFlagBatch(fileInfo, userId, null, delFileIdList, // 基于自身ID的条件FileDelFlagEnums.USING.getFlag()
);
递归操作解析与示例
一、递归原理图解
二、代码中的递归实现
private void findAllSubFolderFileList(List<String> fileIdList, String userId, String fileId, Integer delFlag) {// 1. 将当前文件夹ID加入结果集fileIdList.add(fileId); // 2. 查询当前文件夹下的所有子文件夹FileInfoQuery query = new FileInfoQuery();query.setUserId(userId);query.setFilePid(fileId); // 关键:设置父ID条件query.setDelFlag(delFlag);query.setFolderType(FileFolderTypeEnums.FOLDER.getType());// 3. 获取子文件夹列表List<FileInfo> subFolders = this.fileInfoMapper.selectList(query);// 4. 递归处理每个子文件夹for (FileInfo subFolder : subFolders) {findAllSubFolderFileList(fileIdList, userId, subFolder.getFileId(), delFlag);}
}
三、递归执行过程示例
原始文件夹结构
根文件夹 (fileId: "F0")
├─ 子文件夹1 (fileId: "F1", filePid: "F0") ← 用户选中要删除的
│ ├─ 文件1 (fileId: "F11", filePid: "F1")
│ └─ 子文件夹2 (fileId: "F12", filePid: "F1")
│ └─ 文件2 (fileId: "F121", filePid: "F12")
└─ 子文件夹3 (fileId: "F2", filePid: "F0") ← 用户同时选中的另一个独立文件夹
执行后状态变化
文件/文件夹 | 原状态 | 新状态 | 可见性 |
---|---|---|---|
F1 (选中的文件夹) | USING (0) | RECYCLE (2) | 回收站可见 |
F11 | USING (0) | DEL (1) | 回收站不可见 |
F12 | USING (0) | DEL (1) | 回收站不可见 |
F121 | USING (0) | DEL (1) | 回收站不可见 |
F2 (选中的文件夹) | USING (0) | RECYCLE (2) | 回收站可见 |
递归调用栈演示
四、递归过程详解
1. 递归调用栈
// 第一轮递归(处理F1)
findAllSubFolderFileList(list, "user1", "F1", 0)|- 添加F1到list|- 发现子项F11(文件)、F12(文件夹)|- 处理F12:|- 添加F12到list|- 发现子项F121(文件)
2. 最终生成的ID列表
delFilePidList = ["F1", "F12", "F121"] // 所有包含子项的文件夹ID
delFileIdList = ["F1", "F2"] // 用户直接选中的ID
五、状态转换验证
代码:
/*** 批量将文件/文件夹移动到回收站* @param userId 用户ID* @param fileIds 要删除的文件ID列表,多个用逗号分隔*/
@Override
public void removeFile2RecycleBatch(String userId, String fileIds) {// 1. 参数预处理:将逗号分隔的字符串转为数组String[] fileIdArray = fileIds.split(",");// 2. 构建查询条件:查询用户选中的有效文件FileInfoQuery query = new FileInfoQuery();query.setUserId(userId); // 限制用户权限query.setFileIdArray(fileIdArray); // 设置目标文件IDquery.setDelFlag(FileDelFlagEnums.USING.getFlag()); // 只查询未删除的文件(del_flag=0)// 3. 执行查询获取文件列表List<FileInfo> fileInfoList = this.fileInfoMapper.selectList(query);if (fileInfoList.isEmpty()) {return; // 如果没有符合条件的文件直接返回}// 4. 递归查找所有需要删除的子文件夹(深度优先遍历)List<String> delFilePidList = new ArrayList<>(); // 存储所有子文件夹IDfor (FileInfo fileInfo : fileInfoList) {// 只处理文件夹类型(文件不需要递归)if(FileFolderTypeEnums.FOLDER.getType().equals(fileInfo.getFolderType())) {findAllSubFolderFileList(delFilePidList, userId, fileInfo.getFileId(), FileDelFlagEnums.USING.getFlag());}}// 5. 批量更新子文件状态为完全删除(del_flag=1)if(!delFilePidList.isEmpty()) {FileInfo updateInfo = new FileInfo();updateInfo.setDelFlag(FileDelFlagEnums.DEL.getFlag()); // 设置删除状态// 执行批量更新:将这些子文件夹下的所有内容标记为删除this.fileInfoMapper.updateFileDelFlagBatch(updateInfo, userId, delFilePidList, null, FileDelFlagEnums.USING.getFlag());}// 6. 将用户选中的文件/文件夹标记为回收站状态(del_flag=2)List<String> delFileIdList = Arrays.asList(fileIdArray); // 用户原始选择的文件IDFileInfo fileInfo = new FileInfo();fileInfo.setRecoveryTime(new Date()); // 设置回收时间fileInfo.setDelFlag(FileDelFlagEnums.RECYCLE.getFlag()); // 设置回收站状态// 执行批量更新:将用户直接选中的文件放入回收站this.fileInfoMapper.updateFileDelFlagBatch(fileInfo, userId, null, delFileIdList, FileDelFlagEnums.USING.getFlag());
}/*** 递归查找所有子文件夹* @param fileIdList 结果收集列表(输出参数)* @param userId 用户ID(权限控制)* @param fileId 当前处理的文件夹ID* @param delFlag 文件状态筛选条件(0=正常)*/
private void findAllSubFolderFileList(List<String> fileIdList, String userId, String fileId, Integer delFlag) {// 1. 将当前文件夹ID加入结果集fileIdList.add(fileId);// 2. 构建查询条件:查找当前文件夹下的子文件夹FileInfoQuery query = new FileInfoQuery();query.setUserId(userId); // 用户隔离query.setFilePid(fileId); // 子项条件:parent_id=当前文件夹IDquery.setDelFlag(delFlag); // 状态条件:del_flag=0query.setFolderType(FileFolderTypeEnums.FOLDER.getType()); // 只查询文件夹类型// 3. 查询子文件夹列表List<FileInfo> fileInfoList = this.fileInfoMapper.selectList(query);// 4. 递归处理每个子文件夹for (FileInfo fileInfo : fileInfoList) {findAllSubFolderFileList(fileIdList, userId, fileInfo.getFileId(), delFlag);}
}