# TreeStructureForSpring迭代方式生成树形节点
**Repository Path**: piwood/node-tree
## Basic Information
- **Project Name**: TreeStructureForSpring迭代方式生成树形节点
- **Description**: java 工具类,将id,pid 形式的数据生成前端控件常用的 parent-> children 结构。提供 Springboot starter, 可以直接集成使用。
- **Primary Language**: Java
- **License**: MIT
- **Default Branch**: dev
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 5
- **Forks**: 3
- **Created**: 2020-04-16
- **Last Updated**: 2025-09-02
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 迭代方式生成树形节点
#### 介绍
将id,pid 形式的数据生成 parent-> children 树形结构。
#### 软件架构
jdk8.0+maven3
spring-boot 3.4.2
#### 使用说明
##### 基于 NodeTree 注解返回值转化为属性结构
1. 引入 node-tree-spring-boot-starter 包
```xml
com.sharkman
node-tree-spring-boot-starter
3.0.0
```
2. 创建树节点类
树节点对象既支持使用注解标注 id ,pid ,children 属性
也支持不使用注解标注,实现 Treeable 接口
程序会自动识别使用哪种形式。
```java
// 注解版
// 示例使用 lombok 生成 getter and setter
@Getter
@Setter
public final class TreeNode {
@NodeID
private String id;
@NodePID
private String pId;
@NodeChildren
private List children;
// 其他属性和方法...
}
// 实现接口版
// 示例使用 lombok 生成 getter and setter
@Getter
@Setter
public final class TreeNode implements Treeable {
private String id;
private String pId;
private List children;
// 可添加其他属性以及方法,如
private String nodeType;
}
```
3. 在返回值需要转化为树形式的方法上加上 @NodeTree 注解
> 前提,方法的返回值必须是 List<节点对象> , 节点对象可使用注解标注或实现接口。
- 场景一:固定根节点id 或 pid 为固定值
> 注意: 如果 id 和 pid 都填值,则以 id 为准。
```java
// 根节点 pid 为固定值 0
@NodeTree(pid = "0")
public List findAllNodes(int nodesCount) {
int maxChild = 2;
return AutoData.makeRandomNodes(nodesCount, maxChild, "0");
}
// 注意,如果 TreeNode 实现了Treeable 接口,那么返回值写接口或者实现类均可,即
// 返回值是 List List 均可,下不赘述
// 根节点 id 为固定值 0
@NodeTree(id = "0")
public List findAllNodes(int nodesCount) {
int maxChild = 2;
return AutoData.makeRandomNodes(nodesCount, maxChild, "0");
}
// 根节点 pid 为 null
@NodeTree(isPidNull = true)
public List findAllNodes(int nodesCount) {
int maxChild = 2;
return AutoData.makeRandomNodes(nodesCount, maxChild, "0");
}
```
- 场景二:动态传入根节点id 或 pid,且id 和 pid 为方法参数
```java
// 通过 Id 获取, 方法参数个数不限,在对应参数前加注解即可
@NodeTree
public List findAllNodesByCorpId(@RootID String corpId) {
return corpRepository.findCorpTreeByCorpId(corpId);
}
// 通过 父Id 获取,方法参数个数不限,在对应参数前加注解即可
@NodeTree
public List findAllNodesByPCorpId(@RootPID String corpId) {
return corpRepository.findCorpTreeByPCorpId(corpId);
}
```
- 场景三:动态传入根节点id 或 pid,且id 和 pid 为方法参数的对象属性
```java
// 参数对象
@Getter
@Setter
public final class SearchParam {
@RootID
private String corpId; // 此处增加注解,获取对象内部属性值作为 root id
private Date startDate;
private Date endDate;
// 其他属性和方法...
}
// 通过 Id 获取,方法参数个数不限,在对应参数前加注解即可
@NodeTree
public List findAllNodesByCorpId(SearchParam param) {
return corpRepository.findCorpTreeByCorpId(param.getCorp());
}
// 参数对象
@Getter
@Setter
public final class SearchParam {
@RootPID
private String corpId; // 此处增加注解,获取对象内部属性值作为 root pid
private Date startDate;
private Date endDate;
// 其他属性和方法...
}
// 通过 父Id 获取,方法参数个数不限,在对应参数前加注解即可
@NodeTree
public List findAllNodesByPCorpId(SearchParam param) {
return corpRepository.findCorpTreeByPCorpId(param.getCorp());
}
```
##### 直接使用工具类
1. 只需要引入 node-tree-core 包
```xml
com.sharkman
node-tree-core
3.0.0
```
2. 创建树节点类,对象同上
3. 调用 TreeUtil 或 TreeUtilForAnnotation 对应方法实现功能
- 场景1,已知根节点的父id,构造树。 父 id 可以为 null
```java
// 接口形式
// 若根节点唯一
Treeable root = TreeUtil.buildTreeOfRootPId(nodes, rootPid);
// 若根节点不唯一
List root = TreeUtil.buildTreeOfRootPIdForList(nodes, rootPid);
// 注解形式
// 若根节点唯一
TreeNode root = TreeUtilForAnnotation.buildTreeOfRootPId(nodes, rootPid);
// 若根节点不唯一
List root = TreeUtilForAnnotation.buildTreeOfRootPIdForList(nodes, rootPid);
```
- 场景2,已知根节点的id,构造树。
```java
// 若根节点唯一
Treeable root = TreeUtil.buildTreeOfRootId(nodes, rootId);
// 若根节点不唯一
List root = TreeUtil.buildTreeOfRootIdForList(nodes, rootId);
// 注解形式
// 若根节点唯一
TreeNode root = TreeUtilForAnnotation.buildTreeOfRootId(nodes, rootId);
// 若根节点不唯一
List root = TreeUtilForAnnotation.buildTreeOfRootIdForList(nodes, rootId);
```
- 场景3,已知符合根节点的条件,可以使用 lambda 表达式找到根节点,构造树。
```java
// 若根节点唯一
Predicate predicate = vo -> Objects.equals(vo.getPId(), "root") && OrganEnum.isCorp(vo.getNodeType());
Treeable root = TreeUtil.buildTree(nodes, predicate);
// 若根节点不唯一
List root = TreeUtil.buildTreeForList(nodes, predicate);
// 注解形式
TreeNode root = TreeUtilForAnnotation.buildTree(nodes, predicate);
// 若根节点不唯一
List root = TreeUtilForAnnotation.buildTreeForList(nodes, predicate);
```
- 场景4,已知叶子节点,反向找出谱系内父节点,构造树。(此方法从项目中使用,未进行通用性优化。暂时不支持注解版)
> 说明,常用的场景是数据权限进行组织机构过滤,权限只配置人员,但是需要展示有权限的组织树。
> 另外,此方法支持取子树,比如共4级节点,通过4级节点逆向生成树,根节点传入3级id ,则根从传入的3级开始。
```java
// 若根节点唯一
// 起始构造的子节点集合
List ids=xxxx;
// 最终取出的根节
String rootId="root";
List roots=TreeUtil.constructTreeForSpecifyNode(nodes,ids,rootId);
```
##### 性能表现
> 测试代码已添加, 见子项目 node-tree-run AutoDataTest测试类 TODO 待补充
#### 参与贡献
1. Fork 本仓库
2. 新建 feature_xxx 分支
3. 提交代码
4. 新建 Pull Request
#### 特别感谢 JetBrains 免费的开源授权
