Menu实体类
- /**
- * @date: 2022/7/25
- * @FileName: Menu
- * @author: Yan
- * @Des:
- */
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class Menu {
-
- private Integer id;
-
- private String name;
-
- private Integer parentId;
-
- private List
-
- public Menu(Integer id, String name, Integer parentId) {
- this.id = id;
- this.name = name;
- this.parentId = parentId;
- }
-
- }
- 复制代码
创建测试数据List
-
- /**
- * @date: 2022/7/25
- * @FileName: TreeController
- * @author: Yan
- * @Des:
- */
- @RestController
- @RequestMapping("/tree")
- public class TreeController {
-
- public static List<Menu> getMenus(){
- List<Menu> menus = Arrays.asList(
- new Menu(1, "A公司", 0),
- new Menu(2, "a销售部", 14),
- new Menu(3, "财税部", 1),
- new Menu(4, "商务部", 1),
- new Menu(5, "综合部", 1),
- new Menu(6, "a销售1部", 2),
- new Menu(7, "a销售2部", 2),
- new Menu(8, "a销售3部", 2),
- new Menu(9, "a销售4部", 2),
- new Menu(10, "b销售部", 14),
- new Menu(11, "b销售1部", 10),
- new Menu(12, "b销售2部", 10),
- new Menu(13, "人事部", 1),
- new Menu(14, "销售部", 1));
- return menus;
- }
- }
- 复制代码
在TreeController中,写入:
- @RequestMapping
- public List<Menu> getTree(){
- List<Menu> menus = getMenus();
- List<Menu> menusTree = menus.stream()
- .filter(menu -> menu.getParentId() == 0)
- .map(menu -> {
- menu.setChildren(getChildrens(menu, menus));
- return menu;
- })
- .collect(Collectors.toList());
- return menusTree;
- }
-
- public static List<Menu> getChildrens(Menu root, List<Menu> allMenus){
- List<Menu> childrenTree = allMenus.stream()
- .filter(menu -> Objects.equals(menu.getParentId(), root.getId()))
- .peek(menu -> menu.setChildren(getChildrens(menu, allMenus)))
- .collect(Collectors.toList());
- return childrenTree;
- }
- 复制代码
可以看到,我们成功的返回了树形结构
最近看公司项目,经常会碰到一些场景是需要以树形结构展示的,比如说部门树,设备树,分类树等等,但是感觉好像都是需要用到的时候现写的,但是大体的思路是一样的,感觉重复写就有点冗余了,而且对应的树形结构构建又相对麻烦,我就想着抽离一下,做成一个通用的工具类TreeUtil,于是翻了一下别的大佬的文章,学着写了这样的一个工具类。
TreeNode用来表示每个树节点的抽象,即需要生成树的对象需要实现此接口。
-
- /**
- * @date: 2022/7/25
- * @FileName: TreeNode
- * @author: Yan
- * @Des: 树节点父类,所有需要使用TreeUtils工具类形成树形结构等操作的节点都需要实现该接口
- */
- public interface TreeNode<T, RC, LC> {
-
- /**
- * 获取树结点id
- * @return
- */
- T getTreeNodeId();
-
- /**
- * 获取该节点的父节点id
- * @return
- */
- T getParentId();
-
- /**
- * 判断该节点是否为根节点,默认判定
- * @Des 可以用于简单树的组件
- * @return
- */
- boolean isRoot();
-
- /**
- * 自定义父结点的判定规则
- * @param rootCondition
- * @return
- */
- boolean isRoot(RC rootCondition);
-
- /**
- * 自定义子节点(叶子结点)的判定规则
- * @param leafCondition
- * @return
- */
- boolean isChildren(LC leafCondition);
-
- /**
- * 判断是否有子节点
- * @return
- */
- boolean hasChild();
-
- /**
- * 设置结点的子节点列表
- * @param children
- */
- void setChildren(List<? extends TreeNode<T, RC, LC>> children);
- /**
- * 获取所有子节点
- * @return
- */
- List<? extends TreeNode<T, RC, LC>> getChildren();
- /**
- * 获取树的深度
- * @return
- */
- Integer getLevel();
-
- /**
- * 设置树的深度
- */
- void setLevel(Integer level);
- }
- 复制代码
泛型说明:
T 主要定义返回值的类型
RC(rootCondition) 主要是定义根节点 (也就是父节点) 的自定义判定规则需要用到的参数类型
LC(leafCondition) 主要是定义叶子结点(也就是子节点)的自定义判定规则需要用到的参数类型
用于遍历树作自定义操作使用
- /**
- * @date: 2022/7/28
- * @FileName: Handle
- * @author: Yan
- * @Des: 定义一个函数式接口
- */
- @FunctionalInterface
- public interface FunctionHandle <N, K, V> {
- void