提交代码更新0311

This commit is contained in:
lilin 2025-03-11 14:36:56 +08:00
parent 9dccf3c4f9
commit 104572a40a
7 changed files with 984 additions and 688 deletions

View File

@ -64,7 +64,10 @@ public class TsFilesController {
/********************************** /**********************************
* 用途说明: 查询实验数据管理文件夹 * 用途说明: 查询实验数据管理文件夹
* 参数说明 * 参数说明 id 父级ID
* 参数说明 path 路径
* 参数说明nodeId 节点ID
* 参数说明taskId 任务ID
* pageNum 当前页 * pageNum 当前页
* 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果 * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果
***********************************/ ***********************************/
@ -72,9 +75,9 @@ public class TsFilesController {
@GetMapping("/listTsFiles") @GetMapping("/listTsFiles")
@ApiOperation("查询实验数据管理文件夹") @ApiOperation("查询实验数据管理文件夹")
@PreAuthorize("@el.check('select:tsfiles')") @PreAuthorize("@el.check('select:tsfiles')")
public ResponseResult getsListTsFiles(String id, String path) throws Exception { public ResponseResult getsListTsFiles(String id, String path,String nodeId,String taskId) throws Exception {
//分页查询 //分页查询
List<TsFiles> tsfiles = tsFilesService.getsListTsFiles(id, path); List<TsFiles> tsfiles = tsFilesService.getsListTsFiles(id, path,nodeId,taskId);
return ResponseResult.successData(tsfiles); return ResponseResult.successData(tsfiles);
} }
@ -94,12 +97,9 @@ public class TsFilesController {
if (ObjUtil.isEmpty(tsFiles)) { if (ObjUtil.isEmpty(tsFiles)) {
return ResponseResult.error("参数为空"); return ResponseResult.error("参数为空");
} }
Boolean isOk = tsFilesService.addTsFiles(tsFiles);
if (isOk) { return tsFilesService.addTsFiles(tsFiles);
return ResponseResult.success();
} else {
return ResponseResult.error();
}
} }
/*********************************** /***********************************
@ -303,19 +303,19 @@ public class TsFilesController {
/** /**
* 对比两个目录的文件差异 * 对比两个目录的文件差异
* *
* @param ids 勾选的所有数据ID集合 * @param id 勾选的所有数据ID集合
* @return 文件差异列表 * @return 文件差异列表
*/ */
@Log(module = "实验数据管理", value = "对比本地和minio的文件差异") @Log(module = "实验数据管理", value = "对比本地和minio的文件差异")
@PostMapping("/compare") @PostMapping("/compare")
@ApiOperation("对比两个目录的文件差异") @ApiOperation("对比两个目录的文件差异")
public ResponseResult compareDirectories( String ids, String nodeId, String taskId) { public ResponseResult compareDirectories( String id, String nodeId, String taskId) {
try { try {
List<String> dataset = new ArrayList<>(); List<String> dataset = new ArrayList<>();
if (StrUtil.isNotEmpty(ids)) { if (StrUtil.isNotEmpty(id)) {
String[] splitIds = ids.split(","); String[] splitIds = id.split(",");
// 数组转集合 // 数组转集合
dataset = Arrays.asList(splitIds); dataset = Arrays.asList(splitIds);
} }

View File

@ -44,7 +44,7 @@ public interface ITsFilesService extends IService<TsFiles> {
* TsFiles 文档内容 * TsFiles 文档内容
* 返回值说明: com.yfd.platform.config.ResponseResult 返回新增成功或者失败 * 返回值说明: com.yfd.platform.config.ResponseResult 返回新增成功或者失败
***********************************/ ***********************************/
Boolean addTsFiles(TsFiles tsFiles); ResponseResult addTsFiles(TsFiles tsFiles);
/********************************** /**********************************
* 用途说明: 修改试验数据管理-文档内容 * 用途说明: 修改试验数据管理-文档内容
@ -117,7 +117,7 @@ public interface ITsFilesService extends IService<TsFiles> {
* pageNum 当前页 * pageNum 当前页
* 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果 * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果
***********************************/ ***********************************/
List<TsFiles> getsListTsFiles(String id,String path); List<TsFiles> getsListTsFiles(String id,String path,String nodeId,String taskId);

View File

@ -8,6 +8,7 @@ import com.yfd.platform.modules.experimentalData.domain.TsFiles;
import com.yfd.platform.modules.experimentalData.domain.TsNodes; import com.yfd.platform.modules.experimentalData.domain.TsNodes;
import com.yfd.platform.modules.experimentalData.mapper.TsFilesMapper; import com.yfd.platform.modules.experimentalData.mapper.TsFilesMapper;
import com.yfd.platform.modules.experimentalData.mapper.TsNodesMapper; import com.yfd.platform.modules.experimentalData.mapper.TsNodesMapper;
import com.yfd.platform.modules.experimentalData.service.ITsFilesService;
import com.yfd.platform.modules.experimentalData.service.ITsNodesService; import com.yfd.platform.modules.experimentalData.service.ITsNodesService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.modules.specialDocument.domain.Nodes; import com.yfd.platform.modules.specialDocument.domain.Nodes;
@ -34,6 +35,7 @@ import javax.annotation.Resource;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
/** /**
* <p> * <p>
@ -56,6 +58,11 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
@Resource @Resource
private TsFilesMapper tsFilesMapper; private TsFilesMapper tsFilesMapper;
//实验任务文档表
@Resource
private ITsFilesService tsFilesService;
//数据源Mapper //数据源Mapper
@Resource @Resource
private StorageSourceMapper storageSourceMapper; private StorageSourceMapper storageSourceMapper;
@ -218,7 +225,6 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
result.add(nodeWithChildren); // 将当前节点加入结果列表 result.add(nodeWithChildren); // 将当前节点加入结果列表
} }
} }
// 如果当前节点符合条件且没有被添加到result则将其添加 // 如果当前节点符合条件且没有被添加到result则将其添加
if (currentNode.get("nodeName") instanceof String && ((String) currentNode.get("nodeName")).contains(nodeName) && result.isEmpty()) { if (currentNode.get("nodeName") instanceof String && ((String) currentNode.get("nodeName")).contains(nodeName) && result.isEmpty()) {
result.add(currentNode); // 将当前节点添加到结果列表 result.add(currentNode); // 将当前节点添加到结果列表
@ -226,31 +232,6 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
// 返回包含所有符合条件的树结构的列表 // 返回包含所有符合条件的树结构的列表
return result; return result;
// // 如果当前节点是目标节点返回当前节点
// if (currentNode.get("nodeName") instanceof String &&((String) currentNode.get("nodeName")).contains(nodeName)) {
// return Collections.singletonList(currentNode);
// }
//// if (nodeName.equals(currentNode.get("nodeName"))) {
//// return Collections.singletonList(currentNode);
//// }
//
// // 查找当前节点的所有子节点
// List<Map<String, Object>> children = findChildren(allNodes, currentNode.get("nodeId").toString());
//
// // 递归查找目标节点
// for (Map<String, Object> child : children) {
// List<Map<String, Object>> childTree = buildTreeToTargetNode(child, allNodes, nodeName);
// if (!childTree.isEmpty()) {
// // 如果找到目标节点将当前节点加入树中
// Map<String, Object> nodeWithChildren = new HashMap<>(currentNode);
// nodeWithChildren.put("children", childTree);
// return Collections.singletonList(nodeWithChildren);
// }
// }
//
// // 如果未找到目标节点返回空列表
// return new ArrayList<>();
} }
@ -291,56 +272,15 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
} }
//序号 //序号
tsnodes.setNodeOrder(orderno); tsnodes.setNodeOrder(orderno);
//查询数据源
List<StorageSource> storageSources = storageSourceMapper.findAllOrderByOrderNum();
// 获取路径
List<String> pathNodes = new ArrayList<>();
TsNodes nodesData = tsNodesMapper.selectById(tsnodes.getParentId());
// 从当前节点向上遍历直到根节点
while (nodesData != null) {
pathNodes.add(nodesData.getNodeName());
// 如果父节点是 "00"说明已经到了根节点停止遍历
if ("00".equals(nodesData.getParentId())) {
break;
}
// 获取父节点
nodesData = tsNodesMapper.selectById(nodesData.getParentId()); // 修正 nodesData 中获取 parentId
}
// 反转路径使其从根节点到当前节点
Collections.reverse(pathNodes);
String path = "/" + String.join("/", pathNodes);
//判断 local或者minio有没有成功
List<Boolean> results = new ArrayList<>();
for (StorageSource storageSource : storageSources) {
//新增节点的时候 创建文件夹
NewFolderRequest newFolderRequest = new NewFolderRequest();
newFolderRequest.setName(tsnodes.getNodeName());//新建的文件夹名称,示例值(/a/b/c)
newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问则支持请求密码,示例值(123456)
newFolderRequest.setPath(path);//请求路径,示例值(/)
newFolderRequest.setStorageKey(storageSource.getType().toString());//存储源 key,示例值(local minio)
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey());
boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName());
results.add(flag);
}
// 使用Java 8的Stream API检查列表中是否包含true
boolean hasTrue = results.stream().anyMatch(Boolean::booleanValue);
//如果是true 说明至少有一个生成了文件夹 下一步建立表数据
if (hasTrue) {
int valueAdded = tsNodesMapper.insert(tsnodes); int valueAdded = tsNodesMapper.insert(tsnodes);
if (valueAdded == 1) { if (valueAdded == 1) {
LOGGER.info("local和minio新增成功表结构增加成功"); LOGGER.info("tsnodes表结构增加成功");
return ResponseResult.success(); return ResponseResult.success();
} else { } else {
LOGGER.error("local和minio新增成功表结构增加失败"); LOGGER.error("tsnodes表结构增加失败");
return ResponseResult.error(); return ResponseResult.error();
} }
} else {
LOGGER.error("local和minio新增失败");
return ResponseResult.error();
}
} }
/********************************** /**********************************
@ -376,56 +316,12 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
if (count > 0) { if (count > 0) {
return ResponseResult.error("节点名称已存在!"); return ResponseResult.error("节点名称已存在!");
} }
//查询数据源
List<StorageSource> storageSources = storageSourceMapper.findAllOrderByOrderNum();
List<String> pathNodes = new ArrayList<>();
TsNodes nodesData = tsNodesMapper.selectById(tsnodes.getParentId());
// 从当前节点向上遍历直到根节点
while (nodesData != null) {
pathNodes.add(nodesData.getNodeName());
// 如果父节点是 "00"说明已经到了根节点停止遍历
if ("00".equals(nodesData.getParentId())) {
break;
}
// 获取父节点
nodesData = tsNodesMapper.selectById(nodesData.getParentId()); // 修正 nodesData 中获取 parentId
}
// 反转路径使其从根节点到当前节点
Collections.reverse(pathNodes);
String path = String.join("/", pathNodes);
//判断 local或者minio有没有成功
List<Boolean> results = new ArrayList<>();
for (StorageSource storageSource : storageSources) {
//修改文件夹名称
RenameFolderRequest renameFolderRequest = new RenameFolderRequest();
renameFolderRequest.setName(nodeNameOld);//重命名的原文件夹名称,示例值(movie)
renameFolderRequest.setNewName(nodeName);// 重命名后的文件名称,示例值(music)
renameFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问则支持请求密码,示例值(123456)
renameFolderRequest.setPath(path);//请求路径,示例值(/)
renameFolderRequest.setStorageKey(storageSource.getType().toString());//存储源 key,示例值(local minio)
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(renameFolderRequest.getStorageKey());
boolean flag = fileService.renameFolder(renameFolderRequest.getPath(), renameFolderRequest.getName(), renameFolderRequest.getNewName());
results.add(flag);
}
// 使用Java 8的Stream API检查列表中是否包含true
boolean hasTrue = results.stream().anyMatch(Boolean::booleanValue);
//如果是true 说明至少有一个生成了文件夹 下一步建立表数据
if (hasTrue) {
int valueAdded = tsNodesMapper.updateById(tsnodes); int valueAdded = tsNodesMapper.updateById(tsnodes);
if (valueAdded == 1) { if (valueAdded == 1) {
LOGGER.info("local和minio修改成功表结构增加成功"); LOGGER.info("tsnodes表结构修改成功");
return ResponseResult.success(); return ResponseResult.success();
} else { } else {
LOGGER.error("local和minio修改成功表结构增加失败"); LOGGER.error("tsnodes表结构修改失败");
return ResponseResult.error();
}
} else {
LOGGER.error("local和minio修改失败");
return ResponseResult.error(); return ResponseResult.error();
} }
} }
@ -437,105 +333,37 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
***********************************/ ***********************************/
@Override @Override
public boolean deleteTsNodesById(String id) { public boolean deleteTsNodesById(String id) {
// try {
//根据ID 查询当前数据 //根据ID 查询当前数据
TsNodes tsNodes = tsNodesMapper.selectById(id); TsNodes tsNodes = tsNodesMapper.selectById(id);
//删除之前 先拼路径 然后删除本地和minio的文件夹 最后删除表结构 //删除之前 先拼路径 然后删除本地和minio的文件夹 最后删除表结构
// 删除当前节点
int deleteCount = tsNodesMapper.deleteById(id);
//删除当前节点的 文件 //删除当前节点的 文件
QueryWrapper<TsFiles> queryWrapper1 = new QueryWrapper<>(); QueryWrapper<TsFiles> queryWrapper1 = new QueryWrapper<>();
queryWrapper1.eq("node_id", tsNodes.getNodeId()); queryWrapper1.eq("node_id", tsNodes.getNodeId());
queryWrapper1.eq("task_id", tsNodes.getTaskId()); queryWrapper1.eq("task_id", tsNodes.getTaskId());
tsFilesMapper.delete(queryWrapper1); List<TsFiles> tsFiles = tsFilesMapper.selectList(queryWrapper1);
List<String> dataset = new ArrayList<>();
List<String> pathNodes = new ArrayList<>(); if (tsFiles != null && !tsFiles.isEmpty()) {
TsNodes nodesData = tsNodesMapper.selectById(tsNodes.getParentId()); dataset = tsFiles.stream()
// 从当前节点向上遍历直到根节点 .map(TsFiles::getId) // 假设 TsFiles 类中有 getId() 方法
while (nodesData != null) { .collect(Collectors.toList());
pathNodes.add(nodesData.getNodeName());
// 如果父节点是 "00"说明已经到了根节点停止遍历
if ("00".equals(nodesData.getParentId())) {
break;
} }
// 获取父节点 //批量删除TsFiles表数据
nodesData = tsNodesMapper.selectById(nodesData.getParentId()); // 修正 nodesData 中获取 parentId if (dataset.size() > 0) {
} tsFilesService.deleteTsFilesByIds(dataset, "local");
// 反转路径使其从根节点到当前节点
Collections.reverse(pathNodes);
String path = String.join("/", pathNodes);
List<BatchDeleteRequest.DeleteItem> deleteItemList = new ArrayList<>();
BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem();
deleteItemData.setName(tsNodes.getNodeName());
deleteItemData.setPassword("");
deleteItemData.setPath(path);
deleteItemData.setType(FileTypeEnum.FOLDER);
deleteItemList.add(deleteItemData);
//查询数据源
List<StorageSource> storageSources = storageSourceMapper.findAllOrderByOrderNum();
//判断 local或者minio有没有成功
List<Boolean> results = new ArrayList<>();
for (StorageSource storageSource : storageSources) {
BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest();
batchDeleteRequest.setDeleteItems(deleteItemList);
batchDeleteRequest.setStorageKey(storageSource.getKey());
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey());
List<BatchDeleteRequest.DeleteItem> deleteItems = batchDeleteRequest.getDeleteItems();
int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItems);
for (BatchDeleteRequest.DeleteItem deleteItem : deleteItems) {
boolean flag = false;
try {
if (deleteItem.getType() == FileTypeEnum.FILE) {
flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName());
} else if (deleteItem.getType() == FileTypeEnum.FOLDER) {
flag = fileService.deleteFolder(deleteItem.getPath(), deleteItem.getName());
} }
if (flag) {
deleteSuccessCount++;
} else {
deleteFailCount++;
}
} catch (Exception e) {
LOGGER.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e);
deleteFailCount++;
}
}
if (totalCount > 1) {
//return ResponseResult.success("批量删除 " + totalCount + " 个, 删除成功 " + deleteSuccessCount + " 个, 失败 " + deleteFailCount + " 个.");
LOGGER.error("批量删除 " + totalCount + " 个, 删除成功 " + deleteSuccessCount + " 个, 失败 " + deleteFailCount + " 个.");
} else {
//return totalCount == deleteSuccessCount ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败");
LOGGER.error("批量删除 " + totalCount + " 个, 删除成功 " + deleteSuccessCount + " 个, 失败 " + deleteFailCount + " 个.");
}
//如果是1 说明成功删除
if (deleteSuccessCount >= 1) {
results.add(true);
} else {
results.add(false);
}
}
// 使用Java 8的Stream API检查列表中是否包含true
boolean hasTrue = results.stream().anyMatch(Boolean::booleanValue);
if (hasTrue) {
// 递归删除子节点 // 递归删除子节点
deleteChildren(tsNodes.getNodeId(), tsNodes.getTaskId()); deleteChildren(tsNodes.getNodeId(), tsNodes.getTaskId());
// 删除当前节点
int deleteCount = tsNodesMapper.deleteById(id);
if (deleteCount == 1) {
LOGGER.info("tsnodes表结删除改成功");
return true;
} else {
LOGGER.error("tsnodes表结构删除失败");
return false;
} }
return hasTrue;
// } catch (Exception e) {
// // 如果发生异常返回 false
// return false;
// }
} }
/** /**
@ -556,9 +384,22 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
tsNodesMapper.deleteById(child.getNodeId()); // 删除当前子节点 tsNodesMapper.deleteById(child.getNodeId()); // 删除当前子节点
//批量文件的数据 //批量文件的数据
QueryWrapper<TsFiles> queryWrapper1 = new QueryWrapper<>(); QueryWrapper<TsFiles> queryWrapper1 = new QueryWrapper<>();
queryWrapper1.eq("node_id", parentId); queryWrapper1.eq("node_id", child.getNodeId());
queryWrapper1.eq("task_id", taskId); queryWrapper1.eq("task_id", taskId);
tsFilesMapper.delete(queryWrapper1); List<TsFiles> tsFiles = tsFilesMapper.selectList(queryWrapper1);
List<String> dataset = new ArrayList<>();
if (tsFiles != null && !tsFiles.isEmpty()) {
dataset = tsFiles.stream()
.map(TsFiles::getId) // 假设 TsFiles 类中有 getId() 方法
.collect(Collectors.toList());
}
//批量删除TsFiles表数据
if (dataset.size() > 0) {
tsFilesService.deleteTsFilesByIds(dataset, "local");
} }
} }
} }
}

View File

@ -167,14 +167,16 @@ public abstract class AbstractS3BaseFileService<P extends S3BaseParam> extends A
if (path == null || StringUtils.isEmpty(path)) { if (path == null || StringUtils.isEmpty(path)) {
return fileItemList; return fileItemList;
} }
path = ensurePathWithSlash(path); // 确保路径以斜杠开头
String fullPath = StringUtils.trimStartSlashes(StringUtils.concat(param.getBasePath(), path, ZFileConstant.PATH_SEPARATOR));
// 确保路径格式正确并拼接目标文件夹名称name
path = ensurePathWithSlash(path); // 输入 path="/"处理为 "/"
String targetPath = path + name + ZFileConstant.PATH_SEPARATOR; // 目标路径/431/
String fullPath = StringUtils.trimStartSlashes(
StringUtils.concat(param.getBasePath(), targetPath)
);
// 调用时传入 name=null确保递归时不再匹配其他同名文件夹
// 新增 includeAll 参数控制是否包含所有子项 listFilesInDirectory(bucketName, fullPath, targetPath, null, fileItemList, false);
listFilesInDirectory(bucketName, fullPath, path, name, fileItemList, false);
return fileItemList; return fileItemList;
} }
@ -184,11 +186,11 @@ public abstract class AbstractS3BaseFileService<P extends S3BaseParam> extends A
String path, String path,
String name, String name,
List<FileItemResult> fileItemList, List<FileItemResult> fileItemList,
boolean includeAll // 新增参数是否强制包含所有内容 boolean includeAll
) { ) {
ListObjectsRequest listObjectsRequest = new ListObjectsRequest() ListObjectsRequest listObjectsRequest = new ListObjectsRequest()
.withBucketName(bucketName) .withBucketName(bucketName)
.withPrefix(fullPath) .withPrefix(fullPath) // 关键修复直接通过 Prefix 限定目标路径
.withMaxKeys(1000) .withMaxKeys(1000)
.withDelimiter("/"); .withDelimiter("/");
@ -209,15 +211,15 @@ public abstract class AbstractS3BaseFileService<P extends S3BaseParam> extends A
fileName = fileName.substring(1); fileName = fileName.substring(1);
} }
// 包含条件强制包含 名称匹配 // 包含条件强制包含 名称匹配仅在初始调用时检查 name
if (includeAll || StrUtil.isEmpty(name) || fileName.equals(name)) { if (includeAll || name == null || StrUtil.isEmpty(name) || fileName.equals(name)) {
FileItemResult item = new FileItemResult(); FileItemResult item = new FileItemResult();
item.setName(fileName); item.setName(fileName);
item.setSize(s.getSize()); item.setSize(s.getSize());
item.setTime(s.getLastModified()); item.setTime(s.getLastModified());
item.setType(FileTypeEnum.FILE); item.setType(FileTypeEnum.FILE);
item.setPath(path); // 路径保持不变 item.setPath(path);
item.setUrl(getDownloadUrl(ensurePathWithSlash(path) + fileName)); // 确保路径以斜杠开头 item.setUrl(getDownloadUrl(ensurePathWithSlash(path) + fileName));
fileItemList.add(item); fileItemList.add(item);
} }
} }
@ -227,27 +229,27 @@ public abstract class AbstractS3BaseFileService<P extends S3BaseParam> extends A
String folderName = commonPrefix.substring(fullPath.length(), commonPrefix.length() - 1); String folderName = commonPrefix.substring(fullPath.length(), commonPrefix.length() - 1);
if (StrUtil.isEmpty(folderName) || folderName.equals(StringUtils.DELIMITER_STR)) continue; if (StrUtil.isEmpty(folderName) || folderName.equals(StringUtils.DELIMITER_STR)) continue;
// 判断是否匹配名称或需要强制包含 // 匹配条件仅在初始调用时检查 name递归时 name=null 直接包含
boolean matchFolder = includeAll || StrUtil.isEmpty(name) || folderName.equals(name); boolean matchFolder = includeAll || name == null || StrUtil.isEmpty(name) || folderName.equals(name);
if (matchFolder) { if (matchFolder) {
FileItemResult folderItem = new FileItemResult(); FileItemResult folderItem = new FileItemResult();
folderItem.setName(folderName); folderItem.setName(folderName);
folderItem.setType(FileTypeEnum.FOLDER); folderItem.setType(FileTypeEnum.FOLDER);
folderItem.setPath(path); // 路径保持不变 folderItem.setPath(path);
fileItemList.add(folderItem); fileItemList.add(folderItem);
} }
// 递归处理子文件夹如果匹配则强制包含子项 // 递归处理子文件夹name=null强制包含所有子项
String subPath = ensurePathWithSlash(path) + folderName + ZFileConstant.PATH_SEPARATOR; // 确保路径以斜杠开头并正确拼接 String subPath = ensurePathWithSlash(path) + folderName + ZFileConstant.PATH_SEPARATOR;
String subFullPath = commonPrefix; String subFullPath = commonPrefix;
listFilesInDirectory( listFilesInDirectory(
bucketName, bucketName,
subFullPath, subFullPath,
subPath, subPath,
name, null, // 关键修复递归时不再传递 name避免深层匹配
fileItemList, fileItemList,
matchFolder // 关键修改如果父文件夹匹配则强制包含所有子项 matchFolder // 如果父级匹配则强制包含子项
); );
} }

View File

@ -191,40 +191,60 @@ public class LocalServiceImpl extends AbstractProxyTransferService<LocalParam> {
List<FileItemResult> resultList = new ArrayList<>(); List<FileItemResult> resultList = new ArrayList<>();
String basePath = param.getFilePath(); String basePath = param.getFilePath();
// 处理根目录特殊情况 // 1. 构建目标路径确保前后有 /
String fullPath = folderPath.equals("/") String targetPath = formatCombinedPath(folderPath, name); // 关键修改点
? Paths.get(basePath).toString()
: Paths.get(basePath, folderPath).toString(); // 2. 拼接完整物理路径
String fullPath = Paths.get(basePath, targetPath).toString();
File targetDir = new File(fullPath); File targetDir = new File(fullPath);
if (!targetDir.exists()) { if (!targetDir.exists()) {
throw new FileNotFoundException("路径不存在: " + fullPath); throw new FileNotFoundException("路径不存在: " + fullPath);
} }
// 不添加目标文件夹本身到结果列表与示例数据结构一致 // 3. 列出目录内容
// resultList.add(convertToFileItem(targetDir, folderPath));
// 列出目标目录内容
if (targetDir.isDirectory()) { if (targetDir.isDirectory()) {
String effectiveParentPath = folderPath.endsWith("/") listFilesInDirectory(targetDir, targetPath, resultList);
? folderPath
: folderPath + "/";
listFilesInDirectory(targetDir, effectiveParentPath, resultList);
} }
return resultList; return resultList;
} }
/** /**
* 递归列出文件夹下的所有内容 * 构建规范化路径根路径为 /其他路径为 /path/
*/
private String formatCombinedPath(String folderPath, String name) {
StringBuilder pathBuilder = new StringBuilder();
// 处理 folderPath
if (StringUtils.isBlank(folderPath) || folderPath.equals("/")) {
pathBuilder.append("/");
} else {
pathBuilder.append(folderPath.trim());
if (!folderPath.endsWith("/")) {
pathBuilder.append("/");
}
}
// 处理 name
if (StringUtils.isNotBlank(name)) {
String sanitizedName = name.trim().replaceAll("/+", ""); // 防止注入额外路径
pathBuilder.append(sanitizedName).append("/");
}
// 最终格式化替换多斜杠为单斜杠
return pathBuilder.toString().replaceAll("/+", "/");
}
/**
* 递归列出目录内容
*/ */
private void listFilesInDirectory(File directory, String parentPath, List<FileItemResult> resultList) { private void listFilesInDirectory(File directory, String parentPath, List<FileItemResult> resultList) {
File[] files = directory.listFiles(); File[] files = directory.listFiles();
if (files == null) return; if (files == null) return;
for (File file : files) { for (File file : files) {
// 创建文件项父路径不带文件名 // 创建文件项确保路径格式
FileItemResult item = convertToFileItem(file, parentPath); FileItemResult item = convertToFileItem(file, parentPath);
resultList.add(item); resultList.add(item);
@ -237,12 +257,12 @@ public class LocalServiceImpl extends AbstractProxyTransferService<LocalParam> {
} }
/** /**
* 转换文件对象为结果对象 * 转换文件对象为结果对象路径前后带 /
*/ */
private FileItemResult convertToFileItem(File file, String parentPath) { private FileItemResult convertToFileItem(File file, String parentPath) {
FileItemResult item = new FileItemResult(); FileItemResult item = new FileItemResult();
item.setName(file.getName()); item.setName(file.getName());
item.setPath(formatPath(parentPath)); // 父路径不带当前文件名 item.setPath(formatSinglePath(parentPath)); // 关键修改点
item.setType(file.isDirectory() ? FileTypeEnum.FOLDER : FileTypeEnum.FILE); item.setType(file.isDirectory() ? FileTypeEnum.FOLDER : FileTypeEnum.FILE);
item.setSize(file.isDirectory() ? 0 : file.length()); item.setSize(file.isDirectory() ? 0 : file.length());
item.setTime(new Date(file.lastModified())); item.setTime(new Date(file.lastModified()));
@ -250,13 +270,29 @@ public class LocalServiceImpl extends AbstractProxyTransferService<LocalParam> {
} }
/** /**
* 统一格式化路径 * 单一路径格式化规则
* - 根路径返回 /
* - 其他路径返回 /path/
*/ */
private String formatPath(String path) { private String formatSinglePath(String path) {
// 保证路径以/开头且不以/结尾示例数据结构风格 if (StringUtils.isBlank(path)) return "/";
// 替换多斜杠为单斜杠
path = path.replaceAll("/+", "/"); path = path.replaceAll("/+", "/");
if (!path.startsWith("/")) path = "/" + path;
if (path.endsWith("/") && path.length() > 1) path = path.substring(0, path.length()-1); // 确保以 / 开头
if (!path.startsWith("/")) {
path = "/" + path;
}
// 根路径直接返回
if (path.equals("/")) return path;
// 确保以 / 结尾
if (!path.endsWith("/")) {
path += "/";
}
return path; return path;
} }

View File

@ -11,19 +11,19 @@ spring:
druid: druid:
master: master:
driverClassName: com.mysql.cj.jdbc.Driver driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://120.27.210.161:3306/testdb?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true # url: jdbc:mysql://120.27.210.161:3306/testdb?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true
username: testdb # username: testdb
password: 27CTfsyJmZRESmsa # password: 27CTfsyJmZRESmsa
# url: jdbc:mysql://121.37.111.42:33306/filemanagedb?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true url: jdbc:mysql://121.37.111.42:3306/filemanagedb?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true
# username: filemanagedb username: filemanagedb
# password: GAPchydbCKYFjjAa password: GAPchydbCKYFjjAa
mvc: mvc:
pathmatch: pathmatch:
matching-strategy: ant_path_matcher matching-strategy: ant_path_matcher
servlet: servlet:
multipart: multipart:
max-file-size: 30MB max-file-size: 50GB
max-request-size: 100MB max-request-size: 50GB
logging: logging:
file: file:
name: logs/projectname.log name: logs/projectname.log
@ -34,7 +34,7 @@ logging:
# 在线文档: swagger-ui生产环境建议关闭 # 在线文档: swagger-ui生产环境建议关闭
swagger-ui: swagger-ui:
enabled: true enabled: flase
mybatis-plus: mybatis-plus:
configuration: configuration:
default-enum-type-handler: com.yfd.platform.config.MybatisEnumTypeHandler default-enum-type-handler: com.yfd.platform.config.MybatisEnumTypeHandler