详细分析Java的树形工具类(含注释)

目录

  • 前言
  • 1. 基本框架
  • 2. 实战应用

前言

对应的每个子孙属于该父亲,这其实是数据结构的基础知识,那怎么划分怎么归属呢

对应的基本知识推荐如下:

  1. 【数据结构】树和二叉树详细分析(全)
  2. 【数据结构】B树和B+树的笔记详细诠释

1. 基本框架

最基本的树形结构节点,一个自身ID,一个父亲ID,一个孩子ID:

import java.io.Serializable;
import java.util.List;public interface INode<T> extends Serializable {Long getId();Long getParentId();List<T> getChildren();default Boolean getHasChildren() {return false;}
}

其中ForestNodeManager 树形管理类主要表示如下:

  • nodeMap 存储节点,并提供了一些方法来操作节点和管理树状结构
  • getRoot 方法用于获取合并后的树的根节点列表
  • addParentId 方法用于标记尚未创建的父节点
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;public class ForestNodeManager<T extends INode<T>> {/*** 使用 ImmutableMap 存储节点,其中键是节点的ID,值是节点本身。* 这个映射是不可变的,通过调用 Maps.uniqueIndex(nodes, INode::getId) 来创建,其中 INode::getId 是获取节点ID的方法。* * parentIdMap: 使用 HashMap 存储尚未创建的父节点的ID。键是父节点的ID,值是一个占位对象(在这里是空字符串)。*/private final ImmutableMap<Long, T> nodeMap;private final Map<Long, Object> parentIdMap = Maps.newHashMap();/*** 接受一个 List<T> 类型的参数 nodes,并使用 Maps.uniqueIndex 方法将其转换为 ImmutableMap 存储在 nodeMap 中*/public ForestNodeManager(List<T> nodes) {this.nodeMap = Maps.uniqueIndex(nodes, INode::getId);}/*** 接受一个 Long 类型的节点ID作为参数,然后尝试从 nodeMap 中获取对应ID的节点。* 如果存在该节点,则返回节点;否则返回 null。*/public INode<T> getTreeNodeAt(Long id) {return this.nodeMap.containsKey(id) ? (INode)this.nodeMap.get(id) : null;}/*** 接受一个 Long 类型的父节点ID作为参数,将其添加到 parentIdMap 中。* 这个方法用于标记尚未创建的父节点。*/public void addParentId(Long parentId) {this.parentIdMap.put(parentId, "");}/*** 创建一个空的 ArrayList 用于存储树的根节点。* 使用 forEach 遍历 nodeMap 中的每个节点。* 对于每个节点,如果其父节点ID为0(表示是根节点)或者父节点ID在 parentIdMap 中存在(即尚未创建的父节点),则将该节点添加到根节点列表中。* 最后返回根节点列表。*/public List<T> getRoot() {List<T> roots = new ArrayList();this.nodeMap.forEach((key, node) -> {if (node.getParentId() == 0L || this.parentIdMap.containsKey(node.getId())) {roots.add(node);}});return roots;}
}

对于ForestNodeMerger合并类:

包含树状结构节点的列表,根据节点之间的父子关系进行合并,最终返回合并后的树的根节点列表。

import java.util.List;public class ForestNodeMerger {public ForestNodeMerger() {}/*** 对于每个节点,通过 getParentId() 方法获取其父节点的ID。* 如果父节点ID不等于0(即有父节点),则尝试通过 forestNodeManager.getTreeNodeAt() 方法获取父节点。* 如果成功获取到父节点,则将当前节点添加到父节点的子节点列表中。否则,说明父节点尚未被创建,需要通过 forestNodeManager.addParentId() 方法添加到待创建父节点的列表中。* * 最后,通过 forestNodeManager.getRoot() 方法获取合并后的树的根节点列表,并返回这个列表。*/public static <T extends INode<T>> List<T> merge(List<T> items) {ForestNodeManager<T> forestNodeManager = new ForestNodeManager(items);items.forEach((forestNode) -> {if (forestNode.getParentId() != 0L) {INode<T> node = forestNodeManager.getTreeNodeAt(forestNode.getParentId());if (node != null) {node.getChildren().add(forestNode);} else {forestNodeManager.addParentId(forestNode.getId());}}});return forestNodeManager.getRoot();}
}

2. 实战应用

大多数本身Mapper 或者 Service基层都会帮我们实现增删改查,主要是XML文件对数据库的逻辑

本身就是MybatisPlus框架,推荐阅读:

  1. Springboot整合MybatisPlus的基本CRUD(全)
  2. MyBatis-plus从入门到精通(全)

与日常开发差不多,主要是上述中的方法如何套用!


假设要做一个菜单专栏,必须由这种树形结构来管理,好方便那个子类归属那个父类!

在这里插入图片描述
对应的类别如下:

@Data
@TableName("menu")
@ApiModel(value = "Menu对象", description = "Menu对象")
public class Menu implements Serializable {private static final long serialVersionUID = 1L;/*** 主键*/@JsonSerialize(using = ToStringSerializer.class)@ApiModelProperty(value = "主键")@TableId(value = "id", type = IdType.ASSIGN_ID)private Long id;/*** 菜单父主键*/@JsonSerialize(using = ToStringSerializer.class)@ApiModelProperty(value = "菜单父主键")private Long parentId;/*** 菜单编号*/@ApiModelProperty(value = "菜单编号")private String code;/*** 菜单名称*/@ApiModelProperty(value = "菜单名称")private String name;/*** 菜单别名*/@ApiModelProperty(value = "菜单别名")private String alias;/*** 请求地址*/@ApiModelProperty(value = "请求地址")private String path;/*** 菜单资源*/@ApiModelProperty(value = "菜单资源")private String source;/*** 排序*/@ApiModelProperty(value = "排序")private Integer sort;/*** 菜单类型*/@ApiModelProperty(value = "菜单类型")private Integer category;/*** 操作按钮类型*/@ApiModelProperty(value = "操作按钮类型")private Integer action;/*** 是否打开新页面*/@ApiModelProperty(value = "是否打开新页面")private Integer isOpen;/*** 备注*/@ApiModelProperty(value = "备注")private String remark;/*** 是否已删除*/@TableLogic@ApiModelProperty(value = "是否已删除")private Integer isDeleted;@Overridepublic boolean equals(Object obj) {if (this == obj) {return true;}if (obj == null) {return false;}Menu other = (Menu) obj;if (Func.equals(this.getId(), other.getId())) {return true;}return false;}}

对应与前端交互的VO类如下:public class MenuVO extends Menu implements INode<MenuVO>,大部分这里都是这种写法!

@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "MenuVO对象", description = "MenuVO对象")
public class MenuVO extends Menu implements INode<MenuVO> {private static final long serialVersionUID = 1L;/*** 主键ID*/@JsonSerialize(using = ToStringSerializer.class)private Long id;/*** 父节点ID*/@JsonSerialize(using = ToStringSerializer.class)private Long parentId;/*** 子孙节点*/@JsonInclude(JsonInclude.Include.NON_EMPTY)private List<MenuVO> children;/*** 是否有子孙节点*/@JsonInclude(JsonInclude.Include.NON_EMPTY)private Boolean hasChildren;@Overridepublic List<MenuVO> getChildren() {if (this.children == null) {this.children = new ArrayList<>();}return this.children;}/*** 上级菜单*/private String parentName;/*** 菜单类型*/private String categoryName;/*** 按钮功能*/private String actionName;/*** 是否新窗口打开*/private String isOpenName;
}

对应的懒加载实现类主要如下:

	@Overridepublic List<MenuVO> lazyList(Long parentId, Map<String, Object> param) {if (Func.isEmpty(Func.toStr(param.get("parentId")))) {parentId = null;}return baseMapper.lazyList(parentId, param);}

对应获取树形结构的实现类如下:

	@Overridepublic List<MenuVO> tree() {return ForestNodeMerger.merge(baseMapper.tree());}

其中涉及Mapper的方法主要在xml文件中实现:

<select id="tree" resultMap="treeNodeResultMap">select id, parent_id, name as title, id as "value", id as "key" from menu where is_deleted = 0 and category = 1
</select>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/246067.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue实现在线Excel表格功能

目录 1.安装x-data-spreadsheet xlsx 2.引入 3.使用 1.安装x-data-spreadsheet xlsx npm i x-data-spreadsheet xlsx2.引入 import zhCN from "x-data-spreadsheet/src/locale/zh-cn"; import Spreadsheet from "x-data-spreadsheet"; import * as X…

Scala基础知识

scala 1、scala简介 ​ scala是运行在JVM上的多范式编程语言&#xff0c;同时支持面向对象和面向函数式编程。 2、scala解释器 要启动scala解释器&#xff0c;只需要以下几步&#xff1a; 按住windows键 r输入scala即可 在scala命令提示窗口中执行:quit&#xff0c;即可退…

mybatis基础知识

title: mybatis的基础知识创建mybatis数据库&#xff0c;创建user表&#xff0c;在里面添加数据 创建空项目&#xff0c;创建maven模块 导入相关的依赖 在pom.xml文件中导入mysql&#xff0c;junit测试&#xff0c;mybatis依赖。 <!--导入mysql依赖--><dependency&g…

四步搞定国赛!快速入门大小模型融合的AI产品开发

前不久&#xff0c;2024中国大学生服务外包创新创业大赛正式启动&#xff01;作为中国高等教育学会“全国普通高校学科竞赛排行榜”竞赛&#xff0c;飞桨赛道已经吸引了超过200位选手报名参赛。 本文旨在助力“A01-基于文心大模型智能阅卷平台设计”赛道选手&#xff0c;更快地…

7.【SpringBoot3】项目部署、属性配置、多环境开发

1. SpringBoot 项目部署 项目完成后&#xff0c;需要部署到服务器上。 SpringBoot 项目需要经过编译打包生成一个 jar 包&#xff08;借助打包插件 spring-boot-maven-plugin&#xff09;&#xff0c;再将该 jar 包发送或拷贝到服务器上&#xff0c;然后就可以通过执行 java …

手机视频压缩怎么压缩?一键瘦身~

现在手机已经成为我们日常生活中必不可少的工具&#xff0c;而在手机的应用领域中&#xff0c;文件的传输和存储是一个非常重要的问题。很多用户都会遇到这样一个问题&#xff0c;那就是在手机上存储的文件太多太大&#xff0c;导致手机存储空间不足&#xff0c;那么怎么在手机…

Typora 无法导出 pdf 问题的解决

目录 问题描述 解决困难 解决方法 问题描述 Windows 下&#xff0c;以前&#xff08;Windows 11&#xff09; Typora 可以顺利较快地由 .md 导出 .pdf 文件&#xff0c;此功能当然非常实用与重要。 然而&#xff0c;有一次电脑因故重装了系统&#xff08;刷机&#xff09;…

SpringMVC 环境搭建入门

SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架&#xff0c;属于SpringFrameWork 的后续产品&#xff0c;已经融合在 Spring Web Flow 中。 SpringMVC 已经成为目前最主流的MVC框架之一&#xff0c;并且随着Spring3.0 的发布&#xff0c;全面…

论述Python中列表、元组、字典和集合的概念

Python列表是用于存储任意数目、任意类型的数据集合&#xff0c;包含多个元素的有序连续的内存空间&#xff0c;是内置可变序列&#xff0c;或者说可以任意修改。在Python中&#xff0c;列表以方括号&#xff08;[ ]&#xff09;形式编写。 Python元组与Python列表类似&#x…

Flink 集成 Debezium Confluent Avro ( format=debezium-avro-confluent )

博主历时三年精心创作的《大数据平台架构与原型实现:数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行,点击《重磅推荐:建大数据平台太难了!给我发个工程原型吧!》了解图书详情,京东购书链接:https://item.jd.com/12677623.html,扫描左侧二维…

docker生命周期管理命令

文章目录 前言1、docker create2、docker run2.1、常用选项2.2、系统2.3、网络2.4、健康检查 3、docker start/stop/restart4、docker kill5、docker rm6、docker pause/unpause总结 前言 在云原生时代&#xff0c;Docker已成为必不可少的容器管理工具。通过掌握Docker常用的容…

[UE]无法接收OnInputTouchBegin事件

遇到问题 想做一个鼠标按住左键选中Actor拖动而旋转的功能&#xff0c;想法是通过OnInputTouchBeginOnInputTouchEndTick实现。但是却无法接收OnInputTouchBegin与OnInputTouchEnd事件。 解决方案 想要触发OnInputTouchBegin事件 1.需要设置勾选ProjectSettings->Input-&…

.net访问oracle数据库性能问题

问题&#xff1a; 生产环境相同的inser语句在别的非.NET程序相应明显快于.NET程序&#xff0c;执行时间相差比较大&#xff0c;影响正常业务运行&#xff0c;测试环境反而正常。 问题详细诊断过程 问题初步判断诊断过程&#xff1a; 查询插入慢的sql_id 检查对应的执行计划…

Python zip函数

在Python编程中&#xff0c;zip()函数是一个功能强大而灵活的工具&#xff0c;用于将多个可迭代对象&#xff08;如列表、元组、字符串等&#xff09;组合成一个元组的序列。本文将深入探讨zip()函数的用法、语法、示例代码&#xff0c;并探讨其在实际编程中的应用场景。 什么…

HNU-数据挖掘-实验2-数据降维与可视化

数据挖掘课程实验实验2 数据降维与可视化 计科210X 甘晴void 202108010XXX 文章目录 数据挖掘课程实验<br>实验2 数据降维与可视化实验背景实验目标实验数据集说明实验参考步骤实验过程1.对数据进行初步降维2.使用无监督数据降维方法&#xff0c;比如PCA&#xff0c;I…

EasyExcel实现导出图片到excel

pom依赖&#xff1a; <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.0</version> </dependency> 实体类&#xff1a; package com.aicut.monitor.vo;import com.aicut.monit…

Django开发_20_form表单前后端关联(2)

根据上一篇文章的代码,进一步了解掌握GET,POST的运行机制 一、实例代码 views.py: def show_reverse(request):if request.method "GET":return redirect(reverse("work4:fill"))if request.method "POST":hobby request.POST.get("h…

kafka summary

最近整体梳理之前用到的一些东西&#xff0c;回顾Kafka的时候好多东西都忘记了&#xff0c;把一些自己记的比较模糊并且感觉有用的东西整理一遍并且记忆一遍&#xff0c;仅用于记录以备后续回顾 Kafka的哪些场景中使用了零拷贝 生产者发送消息&#xff1a;在 Kafka 生产者发送…

暴力破解

暴力破解工具使用汇总 1.查看密码加密方式 在线网站&#xff1a;https://cmd5.com/ http://www.158566.com/ https://encode.chahuo.com/kali&#xff1a;hash-identifier2.hydra 用于各种服务的账号密码爆破&#xff1a;FTP/Mysql/SSH/RDP...常用参数 -l name 指定破解登录…

windows定时任务的查看、取消、启动和创建

一、查看 Windows 自动执行的指令 1.使用任务计划程序&#xff1a;任务计划程序是 Windows 内置的工具&#xff0c;可以用于创建、编辑和管理计划任务。您可以按照以下步骤查看已设置的计划任务&#xff1a; 1.1 按下 Win R 键&#xff0c;然后输入 “taskschd.msc”&#xff…