java实现多层级目录树详解

╰+攻爆jí腚メ 2024-04-03 10:18 114阅读 0赞

一,引言

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

二,建表建库

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

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

在这里插入图片描述

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

  1. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (0,'顶级','江西',now(),now(),0);
  2. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (0,'顶级','广东',now(),now(),0);
  3. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (0,'顶级','湖南',now(),now(),0);
  4. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (0,'顶级','河北',now(),now(),0);
  5. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (1,'江西','南昌',now(),now(),0);
  6. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (1,'江西','赣州',now(),now(),0);
  7. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (1,'江西','九江',now(),now(),0);
  8. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (1,'江西','佛山',now(),now(),0);
  9. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (2,'广东','广州',now(),now(),0);
  10. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (2,'广东','深圳',now(),now(),0);
  11. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (2,'广东','佛山',now(),now(),0);
  12. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (2,'广东','东莞',now(),now(),0);
  13. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (3,'湖南','长沙',now(),now(),0);
  14. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (3,'湖南','湘潭',now(),now(),0);
  15. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (3,'湖南','岳阳',now(),now(),0);
  16. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (4,'河北','唐山',now(),now(),0);
  17. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (4,'河北','石家庄',now(),now(),0);
  18. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (4,'河北','保定',now(),now(),0);
  19. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (10,'深圳',,'南山',now(),now(),0);
  20. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (10,'深圳',,'福田',now(),now(),0);
  21. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (10,'深圳',,'宝安',,now(),now(),0);
  22. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (10,'深圳',,'龙岗',now(),now(),0);
  23. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (10,'深圳',,'龙华',now(),now(),0);
  24. insert into site (pid,p_name,current_name,created_time,updated_time,is_deleted) VALUES (10,'深圳',,'光明',now(),now(),0);

在这里插入图片描述

三,原理

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

  1. for(int i = 0; i < list.size; i++){
  2. for(int j = 0; j < list.size; j++){
  3. ...
  4. }
  5. }

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

四,代码实现

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

1,实体类

  1. /**
  2. * @author zhenghuisheng
  3. * @date : 2022/10/8
  4. */
  5. @Data
  6. @AllArgsConstructor
  7. @NoArgsConstructor
  8. public class Site implements Serializable {
  9. @TableId(value = "id", type = IdType.ASSIGN_ID)
  10. @JsonSerialize(using = ToStringSerializer.class)
  11. public Long id;
  12. @JsonSerialize(using = ToStringSerializer.class)
  13. public Long pid;
  14. public String pname;
  15. public String currentName;
  16. public Date createdTime;
  17. public Date updatedTime;
  18. public Integer isDeleted;
  19. }

2、dto类

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

  1. @Data
  2. public class SiteDto implements Serializable {
  3. private static final long serialVersionUID = 1L;
  4. //用户id
  5. public Long id;
  6. //父id
  7. public Long pid;
  8. //父级name
  9. public String pname;
  10. //当前名称
  11. public String currentName;
  12. //创建时间
  13. public String createdTime;
  14. //更新时间
  15. public String updatedTime;
  16. //是否删除
  17. public Integer isDeleted;
  18. //子集,用于存储当前目录下面的全部子集
  19. public List<SiteDto> siteDtoList;
  20. }

3,mybatis里面的sql

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.example.demo.mapper.SiteMapper">
  6. <resultMap id="baseMap" type="com.example.demo.pojo.Site">
  7. <id column="id" property="id"></id>
  8. <result column="pid" property="pid"></result>
  9. <result column="p_name" property="pname"></result>
  10. <result column="current_name" property="currentName"></result>
  11. <result column="created_time" property="createdTime"></result>
  12. <result column="updated_time" property="updatedTime"></result>
  13. <result column="is_deleted" property="isDeleted"></result>
  14. </resultMap>
  15. <select id="queryAll" resultMap="baseMap" resultType="com.example.demo.pojo.Site">
  16. select * from site where is_deleted = 0;
  17. </select>
  18. </mapper>

4,Mapper类

  1. /**
  2. * @author zhenghuisheng
  3. * @date : 2022/10/8
  4. */
  5. @Repository
  6. @Mapper
  7. public interface SiteMapper {
  8. List<Site> queryAll();
  9. }

5,service类

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

  1. /**
  2. * @author zhenghuisheng
  3. * @date : 2022/10/8
  4. */
  5. @Service
  6. public class SiteService {
  7. @Autowired
  8. private SiteMapper siteMapper;
  9. public List<SiteDto> queryAll(){
  10. List<SiteDto> datas = new ArrayList<>();
  11. //获取全部数据
  12. List<Site> siteList = siteMapper.queryAll();
  13. if (siteList != null){
  14. //将这个数据赋值到dto里面
  15. List<SiteDto> siteDtoList = siteList.stream().map(site -> {
  16. SiteDto siteDto = new SiteDto();
  17. BeanUtils.copyProperties(site,siteDto);
  18. //时间格式化
  19. siteDto.setCreatedTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(site.createdTime));
  20. siteDto.setUpdatedTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(site.updatedTime));
  21. return siteDto;
  22. }).collect(Collectors.toList());
  23. //遍历全部的数据,利用递归思想,获取全部的子集
  24. siteDtoList.forEach(e ->{
  25. //判断当前id是否为其他数据的父id
  26. List<SiteDto> childrenList = getChildrenList(e.getId(), siteDtoList);
  27. //设置子集,如果到了最后一级,那么直接设置为null,不展示这个属性即可
  28. e.setSiteDtoList(CollectionUtil.isNotEmpty(childrenList ) ? childrenList : null);
  29. });
  30. //获取所有的顶点数据,即最上层数据,该数据的pid为0
  31. //注意这个pid的数据类型,如果数据库为varchar则equals("0") 整型则为equals(0)
  32. List<SiteDto> siteDtoParents = siteDtoList.stream().filter(t -> t.getPid().equals(0L)).collect(Collectors.toList());
  33. datas.addAll(siteDtoParents);
  34. }
  35. return datas;
  36. }
  37. //获取全部的子集合
  38. public static List<SiteDto> getChildrenList(String id,List<SiteDto> list){
  39. //便利全部数据,将需要的数据过滤出来
  40. return list.stream().filter(t-> t.getPid().equals(id)).collect(Collectors.toList());
  41. }
  42. }

7,Contrller类测试

  1. /**
  2. * @author zhenghuisheng
  3. * @date : 2022/10/8
  4. */
  5. @RestController
  6. public class SiteController {
  7. @Autowired
  8. private SiteService siteService;
  9. @RequestMapping("/getAllData")
  10. public List<SiteDto> getAllData(){
  11. return siteService.queryAll();
  12. }
  13. }

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

发表评论

表情:
评论列表 (有 0 条评论,114人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Java读取层级xml文件

    最近在做国际客服北京职场的项目,需要提供一个接口服务端的能力,也就是需要开发一个http+xml的协议,入参和出参均为Map格式,各系统间的请求或应答是以xml格式封装的。在将