树结构数据封装

  • 前言
  • 一、树结构表模式
  • 二、树结构案例
    • 2.1 原生Java递归循环实现
      • 2.1.1 创建实例对象
      • 2.1.2 编写测试类
      • 2.1.3 返回Json结果集
    • 2.2 使用Jdk的Stream流实现
      • 2.2.1 创建实例对象
      • 2.2.2 编写测试类
    • 3.3 使用MyBatis的递归循环
      • 3.1.1 创建表
      • 3.1.2 创建实例对象
      • 3.1.3 编写API接口类
      • 3.1.4 编写MyBatis数据层
      • 3.1.5 返回Json结果集
  • 总结

前言

在日常搬砖中,少不了要写树结构的数据,而且各个企业的树结构表,也建的五花八门,基本都差不多,这篇我们就来封装这样的树结构数据,不管什么门道,通通搞定。


一、树结构表模式

树结构表模式:不用说就明白,也是最常见结构,如下图:


建表结构:

必备三字段:

{"id":"主键","name":"节点名称","pid":"父节点"}

二、树结构案例

下面要说的就是我们常见的单表树结构数据的封装:

2.1 原生Java递归循环实现

2.1.1 创建实例对象

/*** @description: 树结构实体类* @author: DT* @date: 2021/5/7 20:23* @version: v1.0*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TreeEntity {/*** 主键id*/private Long id;/*** 节点名称*/private String name;/*** 父节点*/private Long parentId;/*** 子节点集合*/private List<TreeEntity> children = new ArrayList<>();public TreeEntity(Long id, String name, Long parentId) {this.id = id;this.name = name;this.parentId = parentId;}
}

2.1.2 编写测试类

/*** @description: 构建树结构数据返回* @author: DT* @date: 2021/5/7 20:26* @version: v1.0*/
public class TestTreeBuild {public static void main(String[] args) {List<TreeEntity> list = new ArrayList<>();list.add(new TreeEntity(1L,"贵州省",0L));list.add(new TreeEntity(2L,"贵阳市",1L));list.add(new TreeEntity(3L,"四川省",0L));list.add(new TreeEntity(4L,"成都市",3L));list.add(new TreeEntity(5L,"云南省",0L));// 构建树结构数据返回List<TreeEntity> treeEntityList = buildTree(list);// 输出json树结构数据System.out.println(JSONUtil.parseArray(treeEntityList));}/*** 构建树结构数据*/public static List<TreeEntity> buildTree(List<TreeEntity> entities) {// 最终输出树结构list集合List<TreeEntity> returnList = new ArrayList<>();// 存放所有id集合List<Long> tempList = new ArrayList<>();for (TreeEntity entity : entities) {tempList.add(entity.getId());}// 遍历循环实体表list集合for (TreeEntity treeEntity : entities) {// 如果是顶级节点, 遍历该父节点的所有子节点if (!tempList.contains(treeEntity.getParentId())) {recursionFunction(entities, treeEntity);returnList.add(treeEntity);}}if (returnList.isEmpty()) {returnList = entities;}return returnList;}/*** 递归遍历*/private static void recursionFunction(List<TreeEntity> entities, TreeEntity treeEntity) {// 得到子节点列表List<TreeEntity> childList = getChildList(entities, treeEntity);treeEntity.setChildren(childList);for (TreeEntity tChild : childList) {if (hasChild(entities, tChild)) {recursionFunction(entities, tChild);}}}/*** 得到子节点列表*/private static List<TreeEntity> getChildList(List<TreeEntity> entities, TreeEntity treeEntity) {List<TreeEntity> arrayList = new ArrayList<>();for (TreeEntity n : entities) {if (null != n.getParentId() && n.getParentId().longValue() == treeEntity.getId().longValue()) {arrayList.add(n);}}return arrayList;}/*** 判断是否有下级节点*/private static boolean hasChild(List<TreeEntity> list, TreeEntity t) {return getChildList(list, t).size() > 0;}}

2.1.3 返回Json结果集

[{"parentId": 0,"children": [{"parentId": 1,"children": [],"name": "贵阳市","id": 2}],"name": "贵州省","id": 1},{"parentId": 0,"children": [{"parentId": 3,"children": [],"name": "成都市","id": 4}],"name": "四川省","id": 3},{"parentId": 0,"children": [],"name": "云南省","id": 5}
]

2.2 使用Jdk的Stream流实现

2.2.1 创建实例对象

实例对象同上TreeEntity

2.2.2 编写测试类

public static void main(String[] args) {List<TreeEntity> list = new ArrayList<>();list.add(new TreeEntity(1L,"贵州省",0L));list.add(new TreeEntity(2L,"贵阳市",1L));list.add(new TreeEntity(3L,"四川省",0L));list.add(new TreeEntity(4L,"成都市",3L));list.add(new TreeEntity(5L,"云南省",0L));// 构建树结构数据返回List<TreeEntity> levelMenus = list.stream().filter(p -> p.getParentId().equals(0L)).peek(treeEntity -> treeEntity.setChildren(buildTree(treeEntity, list))).collect(Collectors.toList());// 输出json树结构数据System.out.println(JSONUtil.toJsonStr(levelMenus));}/*** 构建树结构数据*/private static List<TreeEntity> buildTree(TreeEntity treeEntity, List<TreeEntity> list) {List<TreeEntity> children = list.stream().filter(p -> p.getParentId().equals(treeEntity.getId())).peek(menu -> menu.setChildren(buildTree(menu, list))).collect(Collectors.toList());return children;}

输出结果和上面一个还是一样的,这种方式我们节省了很多代码。

我们再继续改造版本,尝试不同的写法

public static void main(String[] args) {List<TreeEntity> list = new ArrayList<>();list.add(new TreeEntity(1L,"贵州省",0L));list.add(new TreeEntity(2L,"贵阳市",1L));list.add(new TreeEntity(3L,"四川省",0L));list.add(new TreeEntity(4L,"成都市",3L));list.add(new TreeEntity(5L,"云南省",0L));// 构建树结构数据返回List<TreeEntity> treeEntityList = null;if(list.size() > 0){treeEntityList =  buildTree(list,0L);}// 输出json树结构数据System.out.println(JSONUtil.toJsonStr(treeEntityList));
}/*** 构建树结构数据*/
public static List<TreeEntity> buildTree(List<TreeEntity> list, Long pid){// 1.查询所有的pid的子类List<TreeEntity> children = list.stream().filter(x -> x.getParentId().equals(pid)).collect(Collectors.toList());// 2.查询所有的非pid的子类List<TreeEntity> successor = list.stream().filter(x -> !x.getParentId().equals(pid)).collect(Collectors.toList());if(children.size() > 0){children.forEach(x -> {if(successor.size() > 0){buildTree(successor,x.getId()).forEach(y -> x.getChildren().add(y));}});}return children;
}

输出结果和上面一个还是一样的,这种方式我可以指定我们父节点的值。

3.3 使用MyBatis的递归循环

3.1.1 创建表

3.1.2 创建实例对象

@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
@TableName("t_tree_entity")
public class TreeEntity implements Serializable {private static final long serialVersionUID = 1L;@TableId(value = "id", type = IdType.AUTO)private Long id;private String name;private Long parentId;@TableField(exist = false)private List<TreeEntity> children = new ArrayList<>();public TreeEntity(Long id, String name, Long parentId) {this.id = id;this.name = name;this.parentId = parentId;}
}

这里我使用了MybatisPlus快速生成我的业务代码:@TableField(exist = false) 如果你的是MyBatis该注解不用管。

3.1.3 编写API接口类

@RestController
@RequestMapping("/api/v1/tree")
public class TreeEntityController {@Autowiredprivate TreeEntityMapper treeEntityMapper;@GetMapping("/getByPid")public List<TreeEntity> getByPid(@RequestParam(value = "id",required = false) Integer id){List<TreeEntity> list = treeEntityMapper.getByPid(id);return list;}
}

3.1.4 编写MyBatis数据层

<!--根据id获取其子节点信息-->
<resultMap id="BaseResultMap" type="com.dt.springbootdemo.entity.TreeEntity"><id column="id" property="id"/><result column="parent_id" property="parentId"/><result column="name" property="name"/>
</resultMap><resultMap id="ExtendResultMap" type="com.dt.springbootdemo.entity.TreeEntity" extends="BaseResultMap"><collection property="children" ofType="com.dt.springbootdemo.entity.TreeEntity"select="getByPid" column="id"/>
</resultMap><select id="getByPid" resultMap="ExtendResultMap">SELECT * FROM t_tree_entity WHERE parent_id = #{pId,jdbcType=INTEGER}
</select>

3.1.5 返回Json结果集

总结

递归算法的核心思想是通过将问题重复分解为同类的或其子问题的方式,从而可以使用统一的解决方式。很多编程语言支持方法或函数自我调用,简单的说,就是在函数或方法体内,自身可以再次调用自身的方法结构。

企业级Java开发树结构数据封装(开发必用)相关推荐

  1. java批量生成订单号_【笔记6-支付及订单模块】从0开始 独立完成企业级Java电商网站开发(服务端)...

    支付模块 实际开发工作中经常会遇见如下场景,一个支付模块,一个订单模块,有一定依赖,一个同事负责支付模块,另一个同事负责订单模块,但是开发支付模块的时候要依赖订单模块的相关类 ,方法,或者工具类,这些 ...

  2. 【笔记6-支付及订单模块】从0开始 独立完成企业级Java电商网站开发(服务端)

    支付模块 实际开发工作中经常会遇见如下场景,一个支付模块,一个订单模块,有一定依赖,一个同事负责支付模块,另一个同事负责订单模块,但是开发支付模块的时候要依赖订单模块的相关类 ,方法,或者工具类,这些 ...

  3. 从0开始 独立完成企业级Java电商网站开发(服务端)

    数据表结构设计 关系设计 为什么不用外键? 分库分表有外键会非常麻烦,清洗数据也很麻烦.数据库内置触发器也不适合采用. 查业务问题的后悔药--时间戳更多Java学习教程+薇老师:hua2021ei c ...

  4. 【笔记2-环境配置及初始化】从0开始 独立完成企业级Java电商网站开发(服务端)

    准备工作 Linux系统安装 云服务器部署 概要 申请和配置 域名的购买.解析.配置.绑定流程 用户创建实操 环境安装及部署 JDK.Tomcat.Maven下载安装及配置 vsftpd下载安装及配置 ...

  5. JEECG 3.7.1版本发布,企业级JAVA快速开发平台

    JEECG 3.7.1 版本发布,企业级JAVA快速开发平台 ----------------------------------------  Version:  Jeecg_3.7.1 项 目:  ...

  6. JavaFast技术特点介绍-企业级JAVA快速开发平台, 内置java代码生成器

    企业级JAVA快速开发平台, 内置代码生成器 - JavaFast快速开发平台 JavaFast是一款基于代码生成器的智能快速开发平台,可以帮助解决java项目中80%的重复工作,让开发者更多关注业务 ...

  7. JEECG 3.6.5版本发布,企业级JAVA快速开发平台

    JEECG 3.6.5版发布,企业级JAVA快速开发平台        JEECG 是一款基于代码生成器的J2EE快速开发平台,开源界"小普元"超越传统商业企业级开发平台.引领新的 ...

  8. JEECG 3.6.3版本发布 企业级JAVA快速开发平台

    JEECG 3.6.3版本发布   企业级JAVA快速开发平台 JEECG(J2EE Code Generation)是一款基于代码生成器的智能开发平台.引领新的开发模式(OnlineCoding模式 ...

  9. jpa oracle 传参int类型判空_企业级Java开发之图解JPA核心构件

    编者按: 企业级的软件开发中,Java一直都是中流砥柱.在Java EE8之后,Oracle公司把企业级Java标准控制权转交Eclipse基金.最新或·和以后的企业级Java将冠名为Jakarta ...

最新文章

  1. 实验四 JSP数据库编程基础
  2. 学python要下载什么-从应用的角度去学习Python--为孩子下载课本
  3. Wireshark网络抓包(四)——工具
  4. 学习Java编程equals()和hashCode()方法
  5. 08服务器许可证安装向导,08_安装部署GRID许可证服务器.pdf
  6. csv 字符串_Python实现json转csv格式
  7. 人间故事馆话题:聊聊那些被骗经历,让其他人不再被骗
  8. xxx is not mapped 错误 解决方案
  9. oracle Lpad()函数和Rpad()函数的用法
  10. php悲观锁怎么做,mysql悲观锁怎么实现?
  11. 数据分析的一些简单思路总结
  12. <树莓派>——无法向U盘写入文件
  13. GIM三维建模设计软件
  14. Java实现FTP文件上传和下载
  15. php 获取xlsx,PHP Excel Reader读取xlsx文件
  16. Java 后端服务的跨域处理
  17. 安卓Timer+TimeTask实现定时器任务
  18. HDU 6148 - Valley Numer(数位DP)
  19. ubuntu16.04下安装dnw和fastboot工具,解决开发板只有uboot系统,没有网络的情况下,通过dnw和fastboot传送文件到开发板
  20. php微信jssdk获取位置,微信公众号获取用户地理位置

热门文章

  1. 丁丁打折网卷能用吗_超市货架上就能买到的好用护发素,平价好用,打折时可以多囤点...
  2. 信息学奥赛一本通 2016:【例4.1】for循环求和
  3. 信息学奥赛一本通(1046:判断一个数能否同时被3和5整除)
  4. 信息学奥赛一本通(1002:输出第二个整数)
  5. 吃奶酪(洛谷-P1433)
  6. LateX在windows中运用MiKTeX
  7. 19 FI配置-财务会计-定义销售/采购税代码
  8. icpc西部区域赛_信息学子在ACMICPC 2020中国(西部)大学生程序设计竞赛中喜获佳绩...
  9. Windows高精度微秒级(并发)定时器实现
  10. CNN是不是一种局部self-attention?