java 查询树结构数据,无限层级树结构通用方法
1、数据库表数据
2、controller层TestTree简单测试
@RestController
@RequestMapping("/test")
public class testTreeController {
@Autowired
private TestTreeService testTreeService;
@GetMapping("/list")
public List<TestTree> List(TestTree tree)
{
List<TestTree> testTrees = testTreeService.getTreeList(tree);
return testTrees;
}
}
3、TestTree实体类
@TableName(value ="test_tree")
@Data
public class TestTree implements TreeNode {
/**
* id
*/
@TableId
private String id;
/**
* 父级id
*/
private String pid;
/**
* 名称
*/
private String name;
/**
* 类型
*/
private String type;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
@TableField(exist = false)
private List childNodeList = new ArrayList<>();
@Override
public void setChildNodeList(List childNodeList) {
this.childNodeList = childNodeList;
}
@Override
public List getChildNodeList() {
return childNodeList;
}
}
4、TestTreeService 接口
public interface TestTreeService extends IService<TestTree> {
/**
* 查找树结构List
* @param tree 查询条件
* @return 树结构结果
*/
List<TestTree> getTreeList(TestTree tree);
}
5、TestTreeServiceImpl 实现类
@Service
public class TestTreeServiceImpl extends ServiceImpl<TestTreeMapper, TestTree>
implements TestTreeService{
public List<TestTree> selectList(TestTree tree) {
LambdaQueryWrapper<TestTree> queryWrapper = new LambdaQueryWrapper();
queryWrapper.eq(ObjectUtil.isNotEmpty(tree.getId()), TestTree::getId, tree.getId());
queryWrapper.like(ObjectUtil.isNotEmpty(tree.getName()), TestTree::getName, tree.getName());
queryWrapper.like(ObjectUtil.isNotEmpty(tree.getType()), TestTree::getType, tree.getType());
return super.list(queryWrapper);
}
@Override
public List<TestTree> getTreeList(TestTree tree) {
//查询数据
List<TestTree> list = this.selectList(tree);
//封装树结构,通用方法,参数为传入的List
List<TestTree> treeList = TreeList.getTreeList(list);
//返回树结构List
return treeList;
}
}
6、构建树结构
6.1、定义TreeNode
public interface TreeNode<E extends TreeNode> {
/**
* 获取节点ID
*/
String getId();
/**
* 获取父ID
*/
String getPid();
void setChildNodeList(List<E> childNodeList);
/**
* 子节点数据
*/
List<E> getChildNodeList();
}
6.2、构建树结构
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 处理树形结构的数据
*/
public final class TreeList {
public static <E extends TreeNode> List<E> getTreeList(List<E> allData){
//通过流操作,过滤出所有pid为空或者为null的节点,就是树的顶层节点
List<E> topNode = allData.stream().filter(item -> Objects.isNull(item) || StrUtil.isBlank(item.getPid())).collect(Collectors.toList());
//移除所有pid为空或为null的节点
allData.removeIf(item->Objects.isNull(item) || StrUtil.isBlank(item.getPid()));
//将剩余节点按pid分租,结果存储在map中,pid作为键,节点列表作为值
Map<String, List<E>> map = allData.stream().collect(Collectors.groupingBy(TreeNode::getPid));
//构建树形结构
buildTree(topNode,map);
//返回顶层节点列表
return topNode;
}
//构建树形结构
public static <E extends TreeNode> void buildTree(List<E> topNode, Map<String,List<E>> map){
for (E node : topNode) {
//遍历顶层节点,如果节点为null,则跳过
if (Objects.isNull(node)){
continue;
}
//获取当前节点的id
String id = node.getId();
//从map中获取其子节点列表
List<E> treeNodes = map.get(id);
//将其设置为当前节点的子节点列表
node.setChildNodeList(treeNodes);
//如果当前节点没有子节点,则继续下一个节点
if (CollectionUtil.isEmpty(treeNodes)){
continue;
}
//对当前节点的子节点列表递归调用buildTree方法,继续构建树形结构
buildTree(treeNodes,map);
}
}
}
7、postman测试
结果
[
{
"id": "1",
"pid": null,
"name": "第一层级",
"type": "1",
"childNodeList": [
{
"id": "2",
"pid": "1",
"name": "第二层级",
"type": "2",
"childNodeList": [
{
"id": "3",
"pid": "2",
"name": "第三层级",
"type": "3",
"childNodeList": [
{
"id": "4",
"pid": "3",
"name": "第四层级",
"type": "4",
"childNodeList": [
{
"id": "5",
"pid": "4",
"name": "第五层级",
"type": "5",
"childNodeList": null
}
]
}
]
},
{
"id": "6",
"pid": "2",
"name": "次二层级",
"type": "6",
"childNodeList": null
}
]
}
]
}
]