springboot树形结构 支持模糊查询,返回匹配节点和父节点,其他节点不返回
package com.me.meterdemo.ds;
import java.util.ArrayList;
import java.util.List;
public class TreeNode {
private Long id;
private String name;
private Long parentId;
private List<TreeNode> children = new ArrayList<>();
// 构造方法
public TreeNode(Long id, String name, Long parentId) {
this.id = id;
this.name = name;
this.parentId = parentId;
}
// Getters and Setters
public Long getId() { return id; }
public String getName() { return name; }
public Long getParentId() { return parentId; }
public List<TreeNode> getChildren() { return children; }
public void addChild(TreeNode child) {
// 防止重复添加
if (children.stream().noneMatch(c -> c.id.equals(child.id))) {
children.add(child);
}
}
}
package com.me.meterdemo.ds;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class TreeMemoryService {
// 内存数据存储
private final Map<Long, TreeNode> nodeMap = new HashMap<>();
// 初始化测试数据
@PostConstruct
private void initData() {
clearAndInitData();
}
private void clearAndInitData() {
nodeMap.clear();
addNode(1L, "集团总部", null);
addNode(2L, "华东公司", 1L);
addNode(3L, "技术部", 2L);
addNode(4L, "开发组", 3L);
addNode(5L, "测试组", 3L);
addNode(6L, "华南公司", 1L);
}
private void addNode(Long id, String name, Long parentId) {
TreeNode node = new TreeNode(id, name, parentId);
nodeMap.put(id, node);
}
/**
* 执行树结构搜索
* @param keyword 查询关键词(可为空)
* @return 符合条件节点及其父节点组成的树结构
*/
public List<TreeNode> search(String keyword) {
// 空关键词返回空结果
if (keyword != null && keyword.trim().isEmpty()) {
return Collections.emptyList();
}
// 获取所有匹配节点
List<TreeNode> matches = nodeMap.values().stream()
.filter(node -> matchesKeyword(node, keyword))
.collect(Collectors.toList());
// 收集需要展示的节点ID(匹配节点+父链)
Set<Long> visibleIds = new LinkedHashSet<>();
matches.forEach(node -> collectParentChain(node, visibleIds));
// 构建精简树结构
return buildPrunedTree(visibleIds);
}
// 判断节点是否匹配关键词
private boolean matchesKeyword(TreeNode node, String keyword) {
return keyword == null ||
node.getName().contains(keyword);
}
// 收集节点及其所有父节点
private void collectParentChain(TreeNode node, Set<Long> ids) {
Long currentId = node.getId();
while (currentId != null) {
if (!ids.add(currentId)) break; // 防止循环
TreeNode current = nodeMap.get(currentId);
currentId = current.getParentId();
}
}
// 构建修剪后的树结构
private List<TreeNode> buildPrunedTree(Set<Long> visibleIds) {
// 创建节点副本防止污染原始数据
Map<Long, TreeNode> visibleNodes = createNodeCopies(visibleIds);
// 构建层级关系
List<TreeNode> roots = new ArrayList<>();
visibleNodes.values().forEach(node -> {
Long parentId = node.getParentId();
if (parentId == null) {
roots.add(node);
} else {
TreeNode parent = visibleNodes.get(parentId);
if (parent != null) {
parent.addChild(node);
}
}
});
return roots;
}
// 创建节点副本(清空原有子节点)
private Map<Long, TreeNode> createNodeCopies(Set<Long> visibleIds) {
return visibleIds.stream()
.map(id -> nodeMap.get(id))
.filter(Objects::nonNull)
.collect(Collectors.toMap(
TreeNode::getId,
orig -> new TreeNode(orig.getId(),
orig.getName(),
orig.getParentId())
));
}
// 重置测试数据(可选)
public void resetData() {
clearAndInitData();
}
}
package com.me.meterdemo.ds;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class TreeDSController {
private final TreeMemoryService treeMemoryService;
public TreeDSController(TreeMemoryService treeService) {
this.treeMemoryService = treeService;
}
@GetMapping("/search")
public List<TreeNode> searchTree(@RequestParam(required = false) String keyword) {
return treeMemoryService.search(keyword);
}
}
springboot树形结构 支持模糊查询,返回匹配节点和父节点,其他节点不返回