更新容器获取
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
package com.jeesite.modules.app;
|
||||
|
||||
|
||||
import com.jeesite.common.config.Global;
|
||||
import com.jeesite.modules.app.Service.MyService;
|
||||
import com.jeesite.modules.app.dao.MyWorkInfo;
|
||||
import com.jeesite.modules.app.dao.info.DockerInfo;
|
||||
import com.jeesite.modules.app.utils.DateUtils;
|
||||
import com.jeesite.modules.app.utils.DockerUtils;
|
||||
import com.jeesite.modules.app.utils.MyUtils;
|
||||
|
||||
import com.jeesite.modules.biz.entity.*;
|
||||
@@ -15,9 +18,13 @@ import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.jeesite.common.web.BaseController.text;
|
||||
import static com.jeesite.common.web.http.ServletUtils.renderResult;
|
||||
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = "${adminPath}/biz/myWork")
|
||||
@@ -32,6 +39,9 @@ public class appStart {
|
||||
@Resource
|
||||
private BizProjectInfoService bizProjectInfoService;
|
||||
|
||||
@Resource
|
||||
private BizMonitorHostService bizMonitorHostService;
|
||||
|
||||
|
||||
@Resource
|
||||
private BizCalendarInfoService bizCalendarInfoService;
|
||||
@@ -88,4 +98,66 @@ public class appStart {
|
||||
return new MyWorkInfo(weatherText, notifyNums, listItems.size(), projectNums, projectInfos.size(), calendarNums, schedules.size(), employees.size());
|
||||
}
|
||||
|
||||
@RequestMapping(value = "dockerList")
|
||||
@ResponseBody
|
||||
public List<DockerInfo> dockerList(DockerInfo dockerInfo) {
|
||||
BizMonitorHost monitorHost = new BizMonitorHost();
|
||||
monitorHost.setHostId(dockerInfo.getHostId());
|
||||
List<BizMonitorHost> bizMonitorHostList = bizMonitorHostService.findList(monitorHost);
|
||||
BizMonitorHost bizMonitorHost = bizMonitorHostList.get(0);
|
||||
if (bizMonitorHost.getIsAuth().equals("1")) {
|
||||
try {
|
||||
DockerUtils dockerUtils = new DockerUtils(bizMonitorHost.getIpAddress(), bizMonitorHost.getCheckTargetPort());
|
||||
return dockerUtils.dockerInfoList(bizMonitorHost.getHostId());
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(value = "restart")
|
||||
@ResponseBody
|
||||
public String restart(DockerInfo dockerInfo) {
|
||||
BizMonitorHost monitorHost = new BizMonitorHost();
|
||||
monitorHost.setHostId(dockerInfo.getHostId());
|
||||
List<BizMonitorHost> bizMonitorHostList = bizMonitorHostService.findList(monitorHost);
|
||||
BizMonitorHost bizMonitorHost = bizMonitorHostList.get(0);
|
||||
if (bizMonitorHost.getIsAuth().equals("1")) {
|
||||
DockerUtils dockerUtils = new DockerUtils(bizMonitorHost.getIpAddress(), bizMonitorHost.getCheckTargetPort());
|
||||
dockerUtils.stopContainer(dockerInfo.getId());
|
||||
dockerUtils.startContainer(dockerInfo.getId());
|
||||
}
|
||||
return renderResult(Global.TRUE, text("重启容器成功!"));
|
||||
}
|
||||
|
||||
@RequestMapping(value = "start")
|
||||
@ResponseBody
|
||||
public String start(DockerInfo dockerInfo) {
|
||||
BizMonitorHost monitorHost = new BizMonitorHost();
|
||||
monitorHost.setHostId(dockerInfo.getHostId());
|
||||
List<BizMonitorHost> bizMonitorHostList = bizMonitorHostService.findList(monitorHost);
|
||||
BizMonitorHost bizMonitorHost = bizMonitorHostList.get(0);
|
||||
if (bizMonitorHost.getIsAuth().equals("1")) {
|
||||
DockerUtils dockerUtils = new DockerUtils(bizMonitorHost.getIpAddress(), bizMonitorHost.getCheckTargetPort());
|
||||
dockerUtils.startContainer(dockerInfo.getId());
|
||||
}
|
||||
return renderResult(Global.TRUE, text("启动容器成功!"));
|
||||
}
|
||||
|
||||
@RequestMapping(value = "stop")
|
||||
@ResponseBody
|
||||
public String stop(DockerInfo dockerInfo) {
|
||||
BizMonitorHost monitorHost = new BizMonitorHost();
|
||||
monitorHost.setHostId(dockerInfo.getHostId());
|
||||
List<BizMonitorHost> bizMonitorHostList = bizMonitorHostService.findList(monitorHost);
|
||||
BizMonitorHost bizMonitorHost = bizMonitorHostList.get(0);
|
||||
if (bizMonitorHost.getIsAuth().equals("1")) {
|
||||
DockerUtils dockerUtils = new DockerUtils(bizMonitorHost.getIpAddress(), bizMonitorHost.getCheckTargetPort());
|
||||
dockerUtils.stopContainer(dockerInfo.getId());
|
||||
}
|
||||
return renderResult(Global.TRUE, text("停止容器成功!"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.jeesite.modules.app.dao.info;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class DockerInfo implements Serializable {
|
||||
|
||||
private String name; // 容器名称
|
||||
private String id; // 容器id
|
||||
private String cid;
|
||||
private String imageName; // 镜像名称
|
||||
private String mapPorts; // 映射端口
|
||||
private String status; // 运行时长
|
||||
private String state; // 运行状态
|
||||
private double cpuUsage; //CPU
|
||||
private double memUsage; // 内存
|
||||
|
||||
private String hostId;
|
||||
|
||||
public DockerInfo() {
|
||||
|
||||
}
|
||||
|
||||
public DockerInfo(String name, String id,String imageName, String mapPorts, String status, String state, double cpuUsage, double memUsage,String hostId) {
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
this.cid = id.substring(0, 12);
|
||||
this.imageName = imageName;
|
||||
this.mapPorts = mapPorts;
|
||||
this.state = state;
|
||||
this.status = status;
|
||||
this.cpuUsage = cpuUsage;
|
||||
this.memUsage = memUsage;
|
||||
this.hostId = hostId;
|
||||
}
|
||||
}
|
||||
@@ -1,66 +1,229 @@
|
||||
package com.jeesite.modules.app.utils;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.github.dockerjava.api.DockerClient;
|
||||
import com.github.dockerjava.api.command.CreateContainerResponse;
|
||||
import com.github.dockerjava.api.command.InspectContainerResponse;
|
||||
import com.github.dockerjava.api.model.Container;
|
||||
import com.github.dockerjava.core.DockerClientBuilder;
|
||||
import com.github.dockerjava.okhttp.OkDockerHttpClient;
|
||||
import com.jeesite.modules.app.dao.info.DockerInfo;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
public class DockerUtils implements AutoCloseable {
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
// 重试次数
|
||||
private static final int RETRY_COUNT = 3;
|
||||
// 重试间隔(秒)
|
||||
private static final int RETRY_INTERVAL = 2;
|
||||
|
||||
public class DockerUtils {
|
||||
private final DockerClient dockerClient;
|
||||
|
||||
/**
|
||||
* 构造Docker客户端连接(重点:调整HTTP客户端超时配置)
|
||||
*
|
||||
* @param dockerIp Docker服务端IP
|
||||
* @param dockerPort Docker服务端端口
|
||||
* @throws IllegalArgumentException IP/端口不合法时抛出
|
||||
*/
|
||||
public DockerUtils(String dockerIp, int dockerPort) {
|
||||
if (dockerIp == null || dockerIp.isBlank()) {
|
||||
throw new IllegalArgumentException("Docker IP地址不能为空");
|
||||
}
|
||||
if (dockerPort <= 0 || dockerPort > 65535) {
|
||||
throw new IllegalArgumentException("Docker端口号必须在1-65535之间");
|
||||
}
|
||||
|
||||
String dockerHostStr = String.format("tcp://%s:%d", dockerIp, dockerPort);
|
||||
URI dockerHost = URI.create(dockerHostStr);
|
||||
|
||||
// 核心调整:增大HTTP客户端超时时间(连接超时60秒,读取超时120秒)
|
||||
OkDockerHttpClient httpClient = new OkDockerHttpClient.Builder()
|
||||
.dockerHost(dockerHost)
|
||||
.connectTimeout(10)
|
||||
.readTimeout(30)
|
||||
.connectTimeout(60) // 连接超时从10秒→60秒
|
||||
.readTimeout(120) // 读取超时从30秒→120秒
|
||||
.build();
|
||||
|
||||
this.dockerClient = DockerClientBuilder.getInstance()
|
||||
.withDockerHttpClient(httpClient)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取容器列表 all true=包含停止容器,false=仅运行中容器
|
||||
* 启动容器(移除无效的withTimeout,保留重试机制+延长HTTP超时)
|
||||
*
|
||||
* @param containerId 容器ID/名称
|
||||
* @return true=启动成功,false=启动失败
|
||||
*/
|
||||
public boolean startContainer(String containerId) {
|
||||
// 1. 参数校验
|
||||
if (containerId == null || containerId.isBlank()) {
|
||||
return false;
|
||||
}
|
||||
// 2. 增加重试机制
|
||||
int retry = 0;
|
||||
while (retry < RETRY_COUNT) {
|
||||
try {
|
||||
// 检查容器是否存在
|
||||
InspectContainerResponse containerInfo = dockerClient.inspectContainerCmd(containerId).exec();
|
||||
// 检查容器是否已启动
|
||||
if (containerInfo.getState().getRunning()) {
|
||||
return true;
|
||||
}
|
||||
// 修复点:移除无效的withTimeout调用,仅保留核心启动逻辑
|
||||
dockerClient.startContainerCmd(containerId).exec();
|
||||
// 等待2秒后验证启动结果(给容器足够的启动时间,避免状态未同步)
|
||||
TimeUnit.SECONDS.sleep(2);
|
||||
InspectContainerResponse afterStart = dockerClient.inspectContainerCmd(containerId).exec();
|
||||
if (afterStart.getState().getRunning()) {
|
||||
System.out.println("容器[" + containerId + "]启动成功(重试次数:" + retry + ")");
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
retry++;
|
||||
// 非最后一次重试时,等待后重试
|
||||
if (retry < RETRY_COUNT) {
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(RETRY_INTERVAL);
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取容器列表
|
||||
*/
|
||||
public List<Container> listContainers(boolean all) {
|
||||
return dockerClient.listContainersCmd().withShowAll(all).exec();
|
||||
try {
|
||||
return dockerClient.listContainersCmd().withShowAll(all).exec();
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建容器(指定镜像+唯一容器名,后台运行)
|
||||
* 封装容器信息为业务模型
|
||||
*/
|
||||
public List<DockerInfo> dockerInfoList(String hostId) {
|
||||
if (hostId == null || hostId.isBlank()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<DockerInfo> dockerInfos = new ArrayList<>();
|
||||
try {
|
||||
List<Container> containers = listContainers(true);
|
||||
for (Container container : containers) {
|
||||
String containerName = container.getNames() != null
|
||||
? String.join("", container.getNames()).replace("/", "")
|
||||
: "未知容器";
|
||||
String portsJson;
|
||||
try {
|
||||
portsJson = OBJECT_MAPPER.writeValueAsString(container.getPorts());
|
||||
} catch (JsonProcessingException e) {
|
||||
System.out.println("容器[" + container.getId() + "]端口信息序列化失败:" + e.getMessage());
|
||||
portsJson = "[]";
|
||||
}
|
||||
dockerInfos.add(new DockerInfo(
|
||||
containerName,
|
||||
container.getId(),
|
||||
container.getImage(),
|
||||
portsJson,
|
||||
container.getStatus(),
|
||||
"running".equals(container.getState()) ? "1" : "0",
|
||||
0,
|
||||
0,
|
||||
hostId
|
||||
));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
return dockerInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建容器(指定镜像+唯一容器名)
|
||||
*/
|
||||
public String createContainer(String image, String containerName) {
|
||||
CreateContainerResponse resp = dockerClient.createContainerCmd(image)
|
||||
.withName(containerName)
|
||||
.withTty(true) // 分配伪终端,后台运行
|
||||
.exec();
|
||||
return resp.getId();
|
||||
if (image == null || image.isBlank()) {
|
||||
throw new IllegalArgumentException("镜像名称不能为空");
|
||||
}
|
||||
if (containerName == null || containerName.isBlank()) {
|
||||
throw new IllegalArgumentException("容器名称不能为空");
|
||||
}
|
||||
try {
|
||||
CreateContainerResponse resp = dockerClient.createContainerCmd(image)
|
||||
.withName(containerName)
|
||||
.withTty(true)
|
||||
.exec();
|
||||
return resp.getId();
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动容器(支持完整ID/短ID/容器名)
|
||||
* 停止容器
|
||||
*/
|
||||
public void startContainer(String containerId) {
|
||||
dockerClient.startContainerCmd(containerId).exec();
|
||||
public boolean stopContainer(String containerId) {
|
||||
if (containerId == null || containerId.isBlank()) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
InspectContainerResponse containerInfo = dockerClient.inspectContainerCmd(containerId).exec();
|
||||
if (!containerInfo.getState().getRunning()) {
|
||||
return true;
|
||||
}
|
||||
dockerClient.stopContainerCmd(containerId).exec();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止容器(支持完整ID/短ID/容器名)
|
||||
* 删除容器
|
||||
*/
|
||||
public void stopContainer(String containerId) {
|
||||
dockerClient.stopContainerCmd(containerId).exec();
|
||||
public boolean removeContainer(String containerId, boolean force) {
|
||||
if (containerId == null || containerId.isBlank()) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
dockerClient.removeContainerCmd(containerId).withForce(force).exec();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除容器 true=强制删除运行中的容器,false=仅删除停止的
|
||||
* 关闭Docker客户端连接,释放资源
|
||||
*/
|
||||
public void removeContainer(String containerId, boolean force) {
|
||||
dockerClient.removeContainerCmd(containerId).withForce(force).exec();
|
||||
@Override
|
||||
public void close() {
|
||||
if (Objects.nonNull(dockerClient)) {
|
||||
try {
|
||||
dockerClient.close();
|
||||
System.out.println("Docker客户端连接已关闭");
|
||||
} catch (Exception e) {
|
||||
System.err.println("关闭Docker客户端连接失败,异常信息:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.jeesite.modules.app.dao.file.FolderItem;
|
||||
import com.jeesite.modules.app.utils.MyUtils;
|
||||
@@ -160,51 +162,49 @@ public class BizFoldersController extends BaseController {
|
||||
@RequestMapping(value = "foldersAll")
|
||||
@ResponseBody
|
||||
public List<Map<String, Object>> foldersAll(BizFolders bizFolders) {
|
||||
// 构建根节点
|
||||
List<Map<String, Object>> treeData = new ArrayList<>();
|
||||
Map<String, Object> rootNode = new HashMap<>();
|
||||
rootNode.put("id", "0");
|
||||
rootNode.put("name", "根目录");
|
||||
rootNode.put("disabled", false);
|
||||
rootNode.put("children", new ArrayList<>());
|
||||
bizFolders.setParentId("0");
|
||||
bizFolders.setIsDeleted(0);
|
||||
List<BizFolders> firstLevelFolders = bizFoldersService.findList(bizFolders);
|
||||
List<Map<String, Object>> firstNodeList = new ArrayList<>();
|
||||
for (BizFolders firstFolder : firstLevelFolders) {
|
||||
Map<String, Object> firstNode = MyUtils.convertToTreeNode(firstFolder, "根目录");
|
||||
BizFolders secondQuery = new BizFolders();
|
||||
secondQuery.setParentId(firstFolder.getFolderId());
|
||||
secondQuery.setIsDeleted(0);
|
||||
List<BizFolders> secondLevelFolders = bizFoldersService.findList(secondQuery);
|
||||
List<Map<String, Object>> secondNodeList = new ArrayList<>();
|
||||
for (BizFolders secondFolder : secondLevelFolders) {
|
||||
Map<String, Object> secondNode = MyUtils.convertToTreeNode(secondFolder, firstFolder.getFolderName());
|
||||
BizFolders thirdQuery = new BizFolders();
|
||||
thirdQuery.setParentId(secondFolder.getFolderId());
|
||||
thirdQuery.setIsDeleted(0);
|
||||
List<BizFolders> thirdLevelFolders = bizFoldersService.findList(thirdQuery);
|
||||
List<Map<String, Object>> thirdNodeList = new ArrayList<>();
|
||||
for (BizFolders thirdFolder : thirdLevelFolders) {
|
||||
Map<String, Object> thirdNode = MyUtils.convertToTreeNode(thirdFolder, secondFolder.getFolderName());
|
||||
BizFolders fourthQuery = new BizFolders();
|
||||
fourthQuery.setParentId(thirdFolder.getFolderId());
|
||||
fourthQuery.setIsDeleted(0);
|
||||
List<BizFolders> fourthLevelFolders = bizFoldersService.findList(fourthQuery);
|
||||
List<Map<String, Object>> fourthNodeList = new ArrayList<>();
|
||||
for (BizFolders fourthFolder : fourthLevelFolders) {
|
||||
Map<String, Object> fourthNode = MyUtils.convertToTreeNode(fourthFolder, thirdFolder.getFolderName());
|
||||
fourthNodeList.add(fourthNode);
|
||||
}
|
||||
thirdNode.put("children", fourthNodeList);
|
||||
thirdNodeList.add(thirdNode);
|
||||
// 1. 一次性查询所有未删除的文件夹
|
||||
BizFolders query = new BizFolders();
|
||||
query.setIsDeleted(0);
|
||||
List<BizFolders> allFolders = bizFoldersService.findList(query);
|
||||
// 2. 按parentId分组,构建映射Map
|
||||
Map<String, List<BizFolders>> folderMap = allFolders.stream()
|
||||
.collect(Collectors.groupingBy(BizFolders::getParentId, Collectors.toList()));
|
||||
// 3. 递归构建树形结构的核心逻辑(内部递归方法)
|
||||
Function<String, List<Map<String, Object>>> buildTree = new Function<String, List<Map<String, Object>>>() {
|
||||
@Override
|
||||
public List<Map<String, Object>> apply(String parentId) {
|
||||
List<Map<String, Object>> nodeList = new ArrayList<>();
|
||||
List<BizFolders> childFolders = folderMap.getOrDefault(parentId, new ArrayList<>());
|
||||
for (BizFolders folder : childFolders) {
|
||||
// 转换为节点
|
||||
Map<String, Object> node = MyUtils.convertToTreeNode(folder,
|
||||
parentId.equals("0") ? "根目录" : getFolderNameById(folderMap, parentId));
|
||||
// 递归获取子节点
|
||||
node.put("children", this.apply(folder.getFolderId()));
|
||||
nodeList.add(node);
|
||||
}
|
||||
secondNode.put("children", thirdNodeList);
|
||||
secondNodeList.add(secondNode);
|
||||
return nodeList;
|
||||
}
|
||||
firstNode.put("children", secondNodeList);
|
||||
firstNodeList.add(firstNode);
|
||||
}
|
||||
rootNode.put("children", firstNodeList);
|
||||
// 辅助方法:根据folderId获取文件夹名称
|
||||
private String getFolderNameById(Map<String, List<BizFolders>> folderMap, String folderId) {
|
||||
for (List<BizFolders> folders : folderMap.values()) {
|
||||
for (BizFolders f : folders) {
|
||||
if (folderId.equals(f.getFolderId())) {
|
||||
return f.getFolderName();
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
};
|
||||
// 4. 构建根节点的子节点并返回
|
||||
rootNode.put("children", buildTree.apply("0"));
|
||||
treeData.add(rootNode);
|
||||
return treeData;
|
||||
}
|
||||
@@ -213,53 +213,47 @@ public class BizFoldersController extends BaseController {
|
||||
@RequestMapping(value = "treeData")
|
||||
@ResponseBody
|
||||
public List<Map<String, Object>> treeFoldersData(BizFolders bizFolders) {
|
||||
// 1. 构建根节点
|
||||
List<Map<String, Object>> treeData = new ArrayList<>();
|
||||
Map<String, Object> rootNode = new HashMap<>();
|
||||
rootNode.put("id", "0");
|
||||
rootNode.put("name", "根目录");
|
||||
rootNode.put("disabled", false);
|
||||
rootNode.put("children", new ArrayList<>());
|
||||
bizFolders.setParentId("0");
|
||||
bizFolders.setIsDeleted(0);
|
||||
List<BizFolders> firstLevelFolders = bizFoldersService.findList(bizFolders);
|
||||
List<Map<String, Object>> firstNodeList = new ArrayList<>();
|
||||
for (BizFolders firstFolder : firstLevelFolders) {
|
||||
Map<String, Object> firstNode = MyUtils.convertToTreeNode(firstFolder, false);
|
||||
BizFolders secondQuery = new BizFolders();
|
||||
secondQuery.setParentId(firstFolder.getFolderId());
|
||||
secondQuery.setIsDeleted(0);
|
||||
List<BizFolders> secondLevelFolders = bizFoldersService.findList(secondQuery);
|
||||
List<Map<String, Object>> secondNodeList = new ArrayList<>();
|
||||
for (BizFolders secondFolder : secondLevelFolders) {
|
||||
Map<String, Object> secondNode = MyUtils.convertToTreeNode(secondFolder, false);
|
||||
BizFolders thirdQuery = new BizFolders();
|
||||
thirdQuery.setParentId(secondFolder.getFolderId());
|
||||
thirdQuery.setIsDeleted(0);
|
||||
List<BizFolders> thirdLevelFolders = bizFoldersService.findList(thirdQuery);
|
||||
List<Map<String, Object>> thirdNodeList = new ArrayList<>();
|
||||
for (BizFolders thirdFolder : thirdLevelFolders) {
|
||||
Map<String, Object> thirdNode = MyUtils.convertToTreeNode(thirdFolder, false);
|
||||
BizFolders fourthQuery = new BizFolders();
|
||||
fourthQuery.setParentId(thirdFolder.getFolderId());
|
||||
fourthQuery.setIsDeleted(0);
|
||||
List<BizFolders> fourthLevelFolders = bizFoldersService.findList(fourthQuery);
|
||||
List<Map<String, Object>> fourthNodeList = new ArrayList<>();
|
||||
for (BizFolders fourthFolder : fourthLevelFolders) {
|
||||
Map<String, Object> fourthNode = MyUtils.convertToTreeNode(fourthFolder, bizFolders.getDescription().equals("add") ? true : false);
|
||||
fourthNode.put("children", new ArrayList<>());
|
||||
fourthNodeList.add(fourthNode);
|
||||
}
|
||||
thirdNode.put("children", fourthNodeList);
|
||||
thirdNodeList.add(thirdNode);
|
||||
// 2. 一次性查询所有未删除的文件夹(仅1次数据库查询)
|
||||
BizFolders query = new BizFolders();
|
||||
query.setIsDeleted(0);
|
||||
List<BizFolders> allFolders = bizFoldersService.findList(query);
|
||||
// 3. 按parentId分组,快速查找子节点
|
||||
Map<String, List<BizFolders>> folderMap = allFolders.stream()
|
||||
.collect(Collectors.groupingBy(BizFolders::getParentId, Collectors.toList()));
|
||||
final List<java.util.function.BiFunction<String, Integer, List<Map<String, Object>>>> recursiveHolder = new ArrayList<>();
|
||||
// 匿名内部类实现递归逻辑(BiFunction:入参parentId+level,出参节点列表)
|
||||
java.util.function.BiFunction<String, Integer, List<Map<String, Object>>> buildTree = new java.util.function.BiFunction<String, Integer, List<Map<String, Object>>>() {
|
||||
@Override
|
||||
public List<Map<String, Object>> apply(String parentId, Integer level) {
|
||||
List<Map<String, Object>> nodeList = new ArrayList<>();
|
||||
// 空值保护:获取当前父ID下的子文件夹
|
||||
List<BizFolders> childFolders = folderMap.getOrDefault(parentId, new ArrayList<>());
|
||||
for (BizFolders folder : childFolders) {
|
||||
// 原业务逻辑:四级节点特殊处理,其他传false
|
||||
boolean flag = level == 4 ? "add".equals(bizFolders.getDescription()) : false;
|
||||
Map<String, Object> node = MyUtils.convertToTreeNode(folder, flag);
|
||||
// 递归调用自身(通过holder获取)
|
||||
List<Map<String, Object>> children = recursiveHolder.get(0).apply(folder.getFolderId(), level + 1);
|
||||
// 无子节点时设为空列表(和原代码一致)
|
||||
node.put("children", children.isEmpty() ? new ArrayList<>() : children);
|
||||
nodeList.add(node);
|
||||
}
|
||||
secondNode.put("children", thirdNodeList);
|
||||
secondNodeList.add(secondNode);
|
||||
return nodeList;
|
||||
}
|
||||
firstNode.put("children", secondNodeList);
|
||||
firstNodeList.add(firstNode);
|
||||
}
|
||||
rootNode.put("children", firstNodeList);
|
||||
};
|
||||
|
||||
// 将递归逻辑放入holder,供内部调用
|
||||
recursiveHolder.add(buildTree);
|
||||
// 5. 从根节点(parentId=0,层级1)开始构建
|
||||
rootNode.put("children", buildTree.apply("0", 1));
|
||||
treeData.add(rootNode);
|
||||
|
||||
return treeData;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user