java实现多层级目录树详解

article/2025/7/30 13:57:25

一,引言

在开发中,经常遇到前端需要实现一个多层级的目录树,那么后端就需要根据这种结构返回对应的数据,因此在这里记录一下本人在开发中是如何实现这个多层级的目录树。

二,建表建库

在建表时,需要注意的是一定要一个Pid和当前id,这样用于实现这个子级和父级的关联。建表语句如下

CREATE TABLE `site` (  `id` bigint(20) NOT NULL AUTO_INCREMENT, `pid` bigint(20) DEFAULT NULL COMMENT '父id', `p_name` varchar(50) DEFAULT NULL COMMENT '父名称', `current_name` varchar(50) DEFAULT NULL COMMENT '当前层级名称', `created_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', `updated_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `is_deleted` tinyint(4) DEFAULT NULL COMMENT '是否删除', PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8;

在这里插入图片描述

可以参考一下我的,也可以自己插入一些数据。接下来插入数据

insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (0,'顶级','江西',now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (0,'顶级','广东',now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (0,'顶级','湖南',now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (0,'顶级','河北',now(),now(),0);insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (1,'江西','南昌',now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (1,'江西','赣州',now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (1,'江西','九江',now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (1,'江西','佛山',now(),now(),0);insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (2,'广东','广州',now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (2,'广东','深圳',now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (2,'广东','佛山',now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (2,'广东','东莞',now(),now(),0);insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (3,'湖南','长沙',now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (3,'湖南','湘潭',now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (3,'湖南','岳阳',now(),now(),0);insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (4,'河北','唐山',now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (4,'河北','石家庄',now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (4,'河北','保定',now(),now(),0);insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (10,'深圳',,'南山',now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (10,'深圳',,'福田',now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (10,'深圳',,'宝安',,now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (10,'深圳',,'龙岗',now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (10,'深圳',,'龙华',now(),now(),0);
insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (10,'深圳',,'光明',now(),now(),0);

在这里插入图片描述

三,原理

就是利用递归思想,将所有的数据遍历,然后是否有其他结点的Pid为当前结点的id,因此这个数据库的表一定要有一个pid。其实就是类似于两个嵌套的for循环,一个用于遍历,一个用于查找。如果查找成功,那么将那个结点做为当前结点的子节点

for(int i = 0; i < list.size; i++){for(int j = 0; j < list.size; j++){...}
}

就是将之前在集合中全部零散的结点,变成一棵树状型的树。然后这个1,4结点就是最上面的顶层结点,其他结点依次遍历加入到这两棵子树的后面,最后将这两棵树加入到一个集合里面,就变成了一棵大树。也可以参考一下后面的代码,将这个原理再理解一下。
在这里插入图片描述

四,代码实现

这里主要使用springboot项目,依赖和数据库连接之类的暂时不讲。可以参考一下我之前写的这篇https://blog.csdn.net/zhenghuishengq/article/details/109510128?spm=1001.2014.3001.5502

1,实体类

/*** @author zhenghuisheng* @date : 2022/10/8*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Site implements Serializable {@TableId(value = "id", type = IdType.ASSIGN_ID)@JsonSerialize(using = ToStringSerializer.class)public Long id;@JsonSerialize(using = ToStringSerializer.class)public Long pid;public String pname;public String currentName;public Date createdTime;public Date updatedTime;public Integer isDeleted;
}

2、dto类

对应上面的实体类,并在里面加入一个siteDtoList字段,用于保存当前结点的子集。

@Data
public class SiteDto implements Serializable {private static final long serialVersionUID = 1L;//用户idpublic Long id;//父idpublic Long pid;//父级namepublic String pname;//当前名称public String currentName;//创建时间public String createdTime;//更新时间public String updatedTime;//是否删除public Integer isDeleted;//子集,用于存储当前目录下面的全部子集public List<SiteDto> siteDtoList;
}

3,mybatis里面的sql

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.SiteMapper"><resultMap id="baseMap" type="com.example.demo.pojo.Site"><id column="id" property="id"></id><result column="pid" property="pid"></result><result column="p_name" property="pname"></result><result column="current_name" property="currentName"></result><result column="created_time" property="createdTime"></result><result column="updated_time" property="updatedTime"></result><result column="is_deleted" property="isDeleted"></result></resultMap><select id="queryAll" resultMap="baseMap" resultType="com.example.demo.pojo.Site">select * from site where is_deleted = 0;</select></mapper>

4,Mapper类

/*** @author zhenghuisheng* @date : 2022/10/8*/
@Repository
@Mapper
public interface SiteMapper {List<Site> queryAll();
}

5,service类

把这个看懂就基本上没问题了

/*** @author zhenghuisheng* @date : 2022/10/8*/
@Service
public class SiteService {@Autowiredprivate SiteMapper siteMapper;public List<SiteDto> queryAll(){List<SiteDto> datas = new ArrayList<>();//获取全部数据List<Site> siteList = siteMapper.queryAll();if (siteList != null){//将这个数据赋值到dto里面List<SiteDto> siteDtoList = siteList.stream().map(site -> {SiteDto siteDto = new SiteDto();BeanUtils.copyProperties(site,siteDto);//时间格式化siteDto.setCreatedTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(site.createdTime));siteDto.setUpdatedTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(site.updatedTime));return siteDto;}).collect(Collectors.toList());//遍历全部的数据,利用递归思想,获取全部的子集siteDtoList.forEach(e ->{//判断当前id是否为其他数据的父idList<SiteDto> childrenList = getChildrenList(e.getId(), siteDtoList);//设置子集,如果到了最后一级,那么直接设置为null,不展示这个属性即可e.setSiteDtoList(childrenList != null ? childrenList : null);});//获取所有的顶点数据,即最上层数据,该数据的pid为0//注意这个pid的数据类型,如果数据库为varchar则equals("0") 整型则为equals(0)List<SiteDto> siteDtoParents = siteDtoList.stream().filter(t -> t.getPid().equals(0L)).collect(Collectors.toList());datas.addAll(siteDtoParents);}return datas;}//获取全部的子集合public static List<SiteDto> getChildrenList(String id,List<SiteDto> list){//便利全部数据,将需要的数据过滤出来return list.stream().filter(t-> t.getPid().equals(id)).collect(Collectors.toList());}
}

7,Contrller类测试

/*** @author zhenghuisheng* @date : 2022/10/8*/
@RestController
public class SiteController {@Autowiredprivate SiteService siteService;@RequestMapping("/getAllData")public List<SiteDto> getAllData(){return siteService.queryAll();}
}

用postman测试一下,结果就出来了
在这里插入图片描述
这样就大功告成了!!


http://chatgpt.dhexx.cn/article/SVcgR2dJ.shtml

相关文章

Linux系统目录树结构以及解释

FHS标准 Filesystem Hierarchy Standard&#xff08;文件系统层次化标准&#xff09;的缩写&#xff0c;多数Linux版本采用这种文件组织形式&#xff0c;类似于Windows操作系统中c盘的文件目录&#xff0c;FHS采用树形结构组织文件。FHS定义了系统中每个区域的用途、所需要的最…

目录树的构造

概述 ”树“在计算机的世界里是一个基本的数据结构&#xff0c;很多地方都能看到”树“的身影。最常见的应该是在各种软件和网页的菜单栏中&#xff0c;多层级的折叠其实就是以一棵树的形式进行展现的&#xff0c;如下图所示&#xff1a; 在树的层级和标签类别比较少&#xf…

兴安雪学运维之:目录树详解

极北之地&#xff0c;兴安之雪&#xff0c;老骥伏枥转战Linux运维&#xff0c;最近根据授课和大略看了FHS3.0&#xff0c;对Linux的目录有了初步的了解&#xff0c;怕人老忘性差&#xff0c;作以记录。 一、目录结构图 Linux的目录是一个倒置的树状结构&#xff0c;最顶层的目录…

【数据结构】B/B-树(目录树)

引言 关于B树的性质 一、B树的结构 二、B树的实现 #include<iostream> using namespace std; #if 1 //5分支Btree #define M 5 //奇数 #define MAXSIZE (M-1) //最多元素个数 #define MINSIZE (M/2) //最少元素个数 //B树 class Btree { public://关键码类型using KeyTy…

【Mybatis】Mybatis将String类型的0存到数据库中的number类型字段中,变成了空;

一、问题 Mybatis将String类型的0存到数据库中的number类型字段中&#xff0c;变成了空&#xff1b; 二、分析 自己写了一个自动写代码的脚本&#xff0c;带入springBatch后&#xff0c;读取文件时&#xff0c;少了序列号0-9的记录&#xff08;10笔一提交&#xff09;&#…

java取数据库number转String

2019独角兽企业重金招聘Python工程师标准>>> BigDecimal bigDecimal(BigDecimal)value; Long lbigDecimal.longValue(); String sbigDecimal.toString(); 转载于:https://my.oschina.net/u/2285090/blog/514110

字符串存入数据库date类型字段

有时候为了计算方便等原因需要将时间以date格式存入数据库&#xff0c;但是前台传过来的数据类型都是字符串&#xff0c;如果将字符串直接插入date类型的字段中会抛&#xff1a;ORA-01861: 文字与格式字符串不匹配。 前台页面有一个表单&#xff0c;如下所示&#xff1a; <…

2018年SCI论文--整合GEO数据挖掘完整复现 八 :STRING数据库构建蛋白质相互作用网络(PPI),cytoscape软件筛选hub基因

文章目录 论文地址STRING数据库PPI网络构建输入差异基因listPPI图保存结果 cytoscape软件筛选hub基因、功能模块输入“string_interactions”文件用cytohHubba插件&#xff0c;筛选top10 Hub基因生存分析用MCODE插件&#xff0c;筛选功能模块 论文地址 STRING数据库 PPI网络构…

string数据库使用和实践第三部分数据处理 流程-参数--后续分析

流程 1.首先要获取蛋白质列表&#xff08;单个/多个&#xff09; 格式&#xff1a;蛋白名称为一个占一行&#xff0c;或者氨基酸序列的通用格式。ID类别&#xff1a;可以为一种&#xff0c;可以为多种混合 2.在对应的数据框中输入蛋白质列表或者上传列表文件后&#xff0c;选择…

spring boot String类型json 存入数据库

效果图&#xff1a; 如图&#xff0c;string类型的json字符串&#xff0c;存入数据库&#xff0c;主要就是解析成map&#xff0c;遍历插入&#xff0c;不多说上干货&#xff1a; PostMapping(value "/currentConfig")public String saveSvConfig(RequestParam(&quo…

jpa @Convert list转String存入数据库

1.问题 list通过jpa直接存入数据库会报错这里需要进行转换 2.代码 1.dto对象 Entity Data Accessors(chain true) public class GameMatch {/*** 主键*/IdGeneratedValue(strategy GenerationType.IDENTITY)private Integer id;/*** 游戏id*/private Integer gameId;/*** …

string数据库使用和实践的第二部分网页展示http://string-db.org/

主页 protein-mode 该模式中&#xff0c;string数据库能够预测到特定物种中的某一个蛋白质的相互作用关系 通过该模式可以获取最多的特异性&#xff0c;但是覆盖面就会较小一些&#xff0c;原因是该模式中&#xff0c;string不会准确的去获取其他物种的直系同源物&#xff0c;取…

蛋白相互作用数据库,STRING使用指南

对于基因组数据分析而言的话&#xff0c;我们能用到网络分析的就是蛋白相互作用分析(protein-protein ineraction, PPI)分析了。 蛋白相互作用分析的数据库有很多&#xff0c;至于为什么选择STRING&#xff0c;还是在于其强大的可视化&#xff0c;以及自定义功能。这样我们可以…

五大常见的数据类型之 String

前言 我们都知道 Redis 提供了丰富的数据类型&#xff0c;常见的有五种&#xff1a;String&#xff08;字符串&#xff09;&#xff0c;Hash&#xff08;哈希&#xff09;&#xff0c;List&#xff08;列表&#xff09;&#xff0c;Set&#xff08;集合&#xff09;、Zset&…

数据库String字符串

char(n) varchar(n) tinyint tinytext text mediumtext longtextchar(0-255)varchar(0-21844) // 63533定长字符串 char()变长字符串 varchar(n) tinytext text mediumtext longtext(4GBtext)-- char varchar tinytext text mediumtext longtext -- 23767-1 21845-1 16383-1…

STRING:蛋白质相互作用(PPI网络)数据库简介

欢迎关注微信公众号《生信修炼手册》! 研究蛋白之间的相互作用网络&#xff0c;有助于挖掘核心的调控基因&#xff0c;目前已经有很多的蛋白质相互作用的数据库&#xff0c;而string绝对是其中覆盖的物种最多&#xff0c;相互作用信息做大的一个&#xff0c;网址如下 https://…

string数据库使用和实践第一部分string数据库介绍

背景 为什么要寻找蛋白质互做关系&#xff1f; 因为只有正确地发现和注释细胞中的所有功能性的相互作用关系&#xff0c;才能对细胞的功能进行系统层面的学习和理解。 大家在收集和展现蛋白质相互作用的信息上&#xff0c;一直在努力地跟上相互作用关系探索的步伐 近年来&#…

解决虚拟机桥接模式无法上网的问题

1.检查IP地址以及网关等信息是否正确 vim /etc/network/interfaces这里设置的是静态ip, auto lo iface lo inet loopback auto eth0 iface eth0 inet stastic address 192.168.43.40 # 设置IP netmask 255.255.255.0 # 设置子网掩码 gateway 192.168.43.19 # 设置网关 首先…

VM虚拟机桥接模式无法联网解决办法

1.桥接模式的意义&#xff1a; 桥接模式----使虚拟机客户机可以和主机在同一网段&#xff0c;这样&#xff0c;和主机同局域网内的其他主机就也可以ping到虚拟机了 2.问题描述&#xff1a; 1.主机和虚拟机客户机相互之间ping不通 2.将虚拟机改为网络模式为NAT模式自动获取I…

虚拟机配置桥接模式(bridge)

使用的Vmware虚拟机软件 需要使用bridge&#xff0c;桥接模式 首先&#xff0c;需要给主机电脑设置IP&#xff0c; 看主机使用的是有线还是无线&#xff0c;使用哪个就设置那个&#xff0c;可以先通过ipconfig/all来查看ip&#xff0c;然后根据实际信息配置网络适配器 手动配置…