热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

java之TreeUtils生成一切对象树形结构案例

这篇文章主要介绍了java之TreeUtils生成一切对象树形结构案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

项目中经常会遇到各种需要以树形结构展示的功能,比较常见的,如菜单树,分类树,部门树等等,如果为每种类型都遍历递归生成树形结构返回给前端,显得有些冗余且麻烦,并且其实逻辑都是一致的,只是遍历的对象不同而已,故其实可以通过面向接口思维,来实现这种通用工具类的实现。

TreeNode用来表示每个树节点的抽象,即需要生成树的对象需要实现此接口。

 /**
   * 树节点父类,所有需要使用{@linkplain TreeUtils}工具类形成树形结构等操作的节点都需要实现该接口
   *
   * @param  节点id类型
   */
  public interface TreeNode {
    /**
     * 获取节点id
     *
     * @return 树节点id
     */
    T id();
    /**
     * 获取该节点的父节点id
     *
     * @return 父节点id
     */
    T parentId();
    /**
     * 是否是根节点
     *
     * @return true:根节点
     */
    boolean root();
    /**
     * 设置节点的子节点列表
     *
     * @param children 子节点
     */
    void setChildren(List<&#63; extends TreeNode> children);
    /**
     * 获取所有子节点
     *
     * @return 子节点列表
     */
    List<&#63; extends TreeNode> getChildren();
  }

TreeUtils用来生成树形结构,以及获取所有叶子节点等操作

/**
 * 树形结构工具类
 *
 * @author meilin.huang
 * @version 1.0
 * @date 2019-08-24 1:57 下午
 */
public class TreeUtils {
  /**
   * 根据所有树节点列表,生成含有所有树形结构的列表
   *
   * @param nodes 树形节点列表
   * @param   节点类型
   * @return 树形结构列表
   */
  public static > List generateTrees(List nodes) {
    List roots = new ArrayList<>();
    for (Iterator ite = nodes.iterator(); ite.hasNext(); ) {
      T node = ite.next();
      if (node.root()) {
        roots.add(node);
        // 从所有节点列表中删除该节点,以免后续重复遍历该节点
        ite.remove();
      }
    }
    roots.forEach(r -> {
      setChildren(r, nodes);
    });
    return roots;
  }
  /**
   * 从所有节点列表中查找并设置parent的所有子节点
   *
   * @param parent 父节点
   * @param nodes 所有树节点列表
   */
  @SuppressWarnings("all")
  public static  void setChildren(T parent, List nodes) {
    List children = new ArrayList<>();
    Object parentId = parent.id();
    for (Iterator ite = nodes.iterator(); ite.hasNext(); ) {
      T node = ite.next();
      if (Objects.equals(node.parentId(), parentId)) {
        children.add(node);
        // 从所有节点列表中删除该节点,以免后续重复遍历该节点
        ite.remove();
      }
    }
    // 如果孩子为空,则直接返回,否则继续递归设置孩子的孩子
    if (children.isEmpty()) {
      return;
    }
    parent.setChildren(children);
    children.forEach(m -> {
      // 递归设置子节点
      setChildren(m, nodes);
    });
  }
  /**
   * 获取指定树节点下的所有叶子节点
   *
   * @param parent 父节点
   * @param   实际节点类型
   * @return 叶子节点
   */
  public static > List getLeafs(T parent) {
    List leafs = new ArrayList<>();
    fillLeaf(parent, leafs);
    return leafs;
  }
  /**
   * 将parent的所有叶子节点填充至leafs列表中
   *
   * @param parent 父节点
   * @param leafs 叶子节点列表
   * @param   实际节点类型
   */
  @SuppressWarnings("all")
  public static  void fillLeaf(T parent, List leafs) {
    List children = parent.getChildren();
    // 如果节点没有子节点则说明为叶子节点
    if (CollectionUtils.isEmpty(children)) {
      leafs.add(parent);
      return;
    }
    // 递归调用子节点,查找叶子节点
    for (T child : children) {
      fillLeaf(child, leafs);
    }
  }
}

具体使用方式之声明树节点对象

@Getter
@Setter
public class ResourceListVO implements TreeNode {
  private Long id;
  private Long pid;
  private Integer type;
  private String name;
  private String icon;
  private String code;
  private Integer status;
  private List children;
  @Override
  public Long id() {
    return this.id;
  }
  @Override
  public Long parentId() {
    return this.pid;
  }
  @Override
  public boolean root() {
    return Objects.equals(this.pid, 0L);
  }
  @Override
  public void setChildren(List children) {
    this.children = children;
  }
}

具体使用方式之调用

 /**
  * 获取账号的资源树
  */
  public List listByAccountId(Long accountId) {
    return TreeUtils.generateTrees(BeanUtils.copyProperties(mapper.selectByAccountId(userId), ResourceListVO.class));
  }

通过使用TreeUtils工具可以统一方便地生成一切对象的树形结构以及其他一些对树的操作,避免对每个对象都用特定代码生成。使用起来就是几个字简洁方便爽歪歪biu特否。

补充知识:TreeUtil 数据库菜单生成无限级树形结构

1、项目需求:

从数据库从加载所有的菜单出来,菜单中有

id,parentId,name字段

希望能有一个工具帮我进行树形结构重组;

实例类:

package com.lming.chcservice.util; 
import lombok.Data; 
import java.util.List;
@Data
public class TreeNode {
  /**
   * 节点id
   */
  private String id;
  /**
   * 父节点 默认0为根节点
   */
  private String parentId;
  /**
   * 节点名称
   */
  private String name;
  /**
   * 是否有子节点
   */
  private boolean hasChild;
 
  public TreeNode(String id, String parentId, String name) {
    this.id = id;
    this.parentId = parentId;
    this.name = name;
  }
}

工具类:

package com.lming.chcservice.util;
 
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
 
/**
 * 树形结构工具类
 *
 * 将一组list对象转成树形结构
 * 该list需符合设定的字段类型
 *
 */
public class TreeUtil { 
 
  public static Map mapArray = new LinkedHashMap(); 
  public List menuCommon;
  public List list = new ArrayList();
 
  public List treeMenu(List menu){
    this.menuCommon = menu;
    for (TreeNode treeNode : menu) {
      Map mapArr = new LinkedHashMap();
      if(treeNode.getParentId().equals("0")){
        setTreeMap(mapArr,treeNode);
        list.add(mapArr);
      }
    }
    return list;
  }
 
  public List<&#63;> menuChild(String id){
    List lists = new ArrayList();
    for(TreeNode a:menuCommon){
      Map childArray = new LinkedHashMap();
      if(a.getParentId() .equals(id)){
        setTreeMap(childArray,a);
        lists.add(childArray);
      }
    }
    return lists;
  }
 
  private void setTreeMap(Map mapArr,TreeNode treeNode){
    mapArr.put("id", treeNode.getId());
    mapArr.put("name", treeNode.getName());
    mapArr.put("parentId", treeNode.getParentId());
    List<&#63;> childrens = menuChild(treeNode.getId());
    if(childrens.size()>0){
      mapArr.put("hasChild",true);
    }
    else{
      mapArr.put("hasChildren",false);
    }
    mapArr.put("childrens", menuChild(treeNode.getId()));
  }
 
  public static void main(String[] args){
 
    List treeNodeList = new ArrayList<>();
    TreeNode treeNode1 = new TreeNode("1","0","首页");
    TreeNode treeNode2 = new TreeNode("2","0","订单");
    TreeNode treeNode3 = new TreeNode("3","1","预约");
    TreeNode treeNode4 = new TreeNode("4","2","捐献");
    TreeNode treeNode5 = new TreeNode("5","4","我的订单");
    TreeNode treeNode6 = new TreeNode("6","5","个人中心");
    TreeNode treeNode7 = new TreeNode("7","6","个人中心2");
    TreeNode treeNode8 = new TreeNode("8","99","个人中心3");
    treeNodeList.add(treeNode1);
    treeNodeList.add(treeNode6);
    treeNodeList.add(treeNode5);
    treeNodeList.add(treeNode3);
    treeNodeList.add(treeNode4);
    treeNodeList.add(treeNode2);
    treeNodeList.add(treeNode7);
    treeNodeList.add(treeNode8); 
 
    TreeUtil treeUtil = new TreeUtil();
    System.out.print(JsonUtil.toJson(treeUtil.treeMenu(treeNodeList))); 
  } 
}

测试结果:

[
 {
  "id": "1",
  "name": "首页",
  "parentId": "0",
  "hasChild": true,
  "childrens": [
   {
    "id": "3",
    "name": "预约",
    "parentId": "1",
    "hasChildren": false,
    "childrens": []
   }
  ]
 },
 {
  "id": "2",
  "name": "订单",
  "parentId": "0",
  "hasChild": true,
  "childrens": [
   {
    "id": "4",
    "name": "捐献",
    "parentId": "2",
    "hasChild": true,
    "childrens": [
     {
      "id": "5",
      "name": "我的订单",
      "parentId": "4",
      "hasChild": true,
      "childrens": [
       {
        "id": "6",
        "name": "个人中心",
        "parentId": "5",
        "hasChild": true,
        "childrens": [
         {
          "id": "7",
          "name": "个人中心2",
          "parentId": "6",
          "hasChildren": false,
          "childrens": []
         }
        ]
       }
      ]
     }
    ]
   }
  ]
 }
]

实力类不一致怎么办? 自己写一个实体转换类,将类的对象属性转换成上面的实体类,然后在调用,当然最快的方式直接修改实体类即可用。

以上这篇java之TreeUtils生成一切对象树形结构案例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。


推荐阅读
  • YOLOv7基于自己的数据集从零构建模型完整训练、推理计算超详细教程
    本文介绍了关于人工智能、神经网络和深度学习的知识点,并提供了YOLOv7基于自己的数据集从零构建模型完整训练、推理计算的详细教程。文章还提到了郑州最低生活保障的话题。对于从事目标检测任务的人来说,YOLO是一个熟悉的模型。文章还提到了yolov4和yolov6的相关内容,以及选择模型的优化思路。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • Android JSON基础,音视频开发进阶指南目录
    Array里面的对象数据是有序的,json字符串最外层是方括号的,方括号:[]解析jsonArray代码try{json字符串最外层是 ... [详细]
  • jmeter实践:从csv中获取带引号的数据详情的技巧和运行全部数据的方法
    本文分享了jmeter实践中从csv中获取带引号的数据的解决办法,包括设置CSV Data Set Config和运行脚本获取数据的方法。另外还介绍了循环运行csv中全部数据的解决方法,避免每次修改csv用例都需要修改脚本的麻烦。通过了解和掌握工具的细节点,可以更好地解决问题和提高技术水平。 ... [详细]
  • 单点登录原理及实现方案详解
    本文详细介绍了单点登录的原理及实现方案,其中包括共享Session的方式,以及基于Redis的Session共享方案。同时,还分享了作者在应用环境中所遇到的问题和经验,希望对读者有所帮助。 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • 使用正则表达式爬取36Kr网站首页新闻的操作步骤和代码示例
    本文介绍了使用正则表达式来爬取36Kr网站首页所有新闻的操作步骤和代码示例。通过访问网站、查找关键词、编写代码等步骤,可以获取到网站首页的新闻数据。代码示例使用Python编写,并使用正则表达式来提取所需的数据。详细的操作步骤和代码示例可以参考本文内容。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 本文介绍了前端人员必须知道的三个问题,即前端都做哪些事、前端都需要哪些技术,以及前端的发展阶段。初级阶段包括HTML、CSS、JavaScript和jQuery的基础知识。进阶阶段涵盖了面向对象编程、响应式设计、Ajax、HTML5等新兴技术。高级阶段包括架构基础、模块化开发、预编译和前沿规范等内容。此外,还介绍了一些后端服务,如Node.js。 ... [详细]
  • React项目中运用React技巧解决实际问题的总结
    本文总结了在React项目中如何运用React技巧解决一些实际问题,包括取消请求和页面卸载的关联,利用useEffect和AbortController等技术实现请求的取消。文章中的代码是简化后的例子,但思想是相通的。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
author-avatar
翔溢_142
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有