三层目录建树

关键思想:

  • 1

最终返回给前台的是一个实体类,该类应该有一个Children字段(实体类属性中具有,或者继承方法来获得,本例子用的是继承)用来接受它的子元素,子元素同样也是该类,也具有Children字段(层层套娃);

  • 2

遍历数据库所有元素,将一级元素(父id等于0)直接添加到树中,(其实就是放在该类中),作为基础;

  • 3

然后嵌套循环进行再次遍历数据库,进行判断,如果有A元素的父id等于另外一个B元素的id,就将A元素添加到B元素的Children字段中进行储存,也就是将A元素作为B元素的子级;遍历完成之后,每个元素具有的子元素都被安排的明明白白,层级关系建立完成

  • 4
    这样返回到前台就是这样的数据
    在这里插入图片描述
    建立完成

具体步骤及演示代码

- 1:数据库建立

数据库元素应该具有自身id,父id来区别层级
在这里插入图片描述

- 2:进行数据库元素的全部查询


@Override
public List<GoodsCategoryTree> selectTree(GoodsCategory goodsCategory) {
   System.out.println("进入selectTree方法。。。");
   List<GoodsCategory> list = this.list(Wrappers.lambdaQuery(goodsCategory));
   System.out.println("打印进入gettree的list"+list);
   return getTree(this.list(Wrappers.lambdaQuery(goodsCategory)));
}

/**
 * 构建树
 *
 * @param entitys
 * @return
 */
private List<GoodsCategoryTree> getTree(List<GoodsCategory> entitys) {
   List<GoodsCategoryTree> treeList = entitys.stream()
         //过滤(当前id不等于它的父类id)
         .filter(entity -> !entity.getId().equals(entity.getParentId()))
         //同级类目,根据Sort排序
         .sorted(Comparator.comparingInt(GoodsCategory::getSort))
         //复制bean
         .map(entity -> {
            GoodsCategoryTree node = new GoodsCategoryTree();
            //转换类型(其实无所谓换不换都一样,两个类基本属性一样)
            //转换后,流输出就变成了List<GoodsCategoryTree>
            BeanUtil.copyProperties(entity,node);
            return node;
         }).collect(Collectors.toList());
         //将返回的list集合放进树形工具类中,处理后返回
   return TreeUtil.build(treeList, CommonConstants.PARENT_ID);
}

①selectTree方法中只是将数据库的数据按照条件查询出来,(一般不限制条件,限制的话也不能限制parentId,限制了会导致树形结构一级没有内容,后面返回到前台的就是空的)并放入getTree方法中;
②getTree方法主要是将查询到的数据转换成流,并进行筛选、排序、转换类等操作,最后以List< GoodsCategoryTree >的形式放入TreeUtil.build()方法中;
③TreeUtil.build()方法是整个树形的核心;通过两层循环,将每个元素都互相做比较,如果是其子类就放进去到它的children字段中,然后将parentId等于0的元素放入需要返回到前台的类中,也就是List< GoodsCategoryTree >类中;返回就是分层的实体类;
代码如下:

/**
 * @author
 */
@UtilityClass
public class TreeUtil {
   /**
    * 两层循环实现建树
    *
    * @param treeNodes 传入的树节点列表
    * @return
    */
   //因为改类继承了TreeNode类,所以才会有该类的addChildren方法
   public <T extends TreeNode> List<T> build(List<T> treeNodes, Object root) {
      //T 类型为 GoodsCategoryTree  root = 0
      List<T> trees = new ArrayList<>();
      //遍历 list中每一个元素为treeNode
      for (T treeNode : treeNodes) {
         //先把父id等于0的,也就是第一级添加到树结构中
         if (root.equals(treeNode.getParentId())) {
            //如果元素父类id为0,就添加
            trees.add(treeNode);
//          trees.sort(Comparator.comparing(TreeNode::getSort));
         }
         //就再次遍历所有,包括已经添加到树中的
         for (T it : treeNodes) {
            //遍历所有,如果有元素的父id等于该元素的id,就成为其子类,不管几层,最后都会按层级排序
            if (it.getParentId().equals(treeNode.getId())) {
               treeNode.addChildren(it);
//             treeNode.getChildren().sort(Comparator.comparing(TreeNode::getSort));
            }

         }
      }
      return trees;
   }

其中泛型T是方法传进来的,这里也就是List< GoodsCategoryTree >类,看一下实体类:

/**
 * 商品类目
 *
 * @author JL
 * @date 2019-08-12 11:46:28
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class GoodsCategoryTree extends TreeNode {

   /**
    * 所属租户
    */
   @ApiModelProperty(value = "所属租户")
   private String tenantId;
   /**
    * (1:开启;0:关闭)
    */
   @ApiModelProperty(value = "1:开启;0:关闭")
   private String enable;
   /**
    * 父分类编号
    */
   @ApiModelProperty(value = "父分类编号")
   private String parentId;
   /**
    * 名称
    */
   @ApiModelProperty(value = "名称")
   private String name;
   /**
    * 描述
    */
   @ApiModelProperty(value = "描述")
   private String description;
   /**
    * 图片
    */
   @ApiModelProperty(value = "图片")
   private String picUrl;
   /**
    * 排序
    */
   @ApiModelProperty(value = "排序")
   private Integer sort;
   /**
    * 创建时间
    */
   @ApiModelProperty(value = "创建时间")
   private LocalDateTime createTime;
   /**
    * 最后更新时间
    */
   @ApiModelProperty(value = "最后更新时间")
   private LocalDateTime updateTime;
   /**
    * 逻辑删除标记(0:显示;1:隐藏)
    */
   @ApiModelProperty(value = "逻辑删除标记")
   private String delFlag;
   /**
    * 跳转页面
    */
   @ApiModelProperty(value = "跳转页面")
   private String page;
}

并没有children字段,但是需要用到这个字段来进行子元素的存储,前文也提到,要么建字段,要么继承有这个字段的类,这里选择的继承类;

//因为改类继承了TreeNode类,所以才会有该类的addChildren方法
public <T extends TreeNode> List<T> build(List<T> treeNodes, Object root)

继承的这个类

package com.uk.mall.cloud.common.core.entity;

import lombok.Data;

import java.util.ArrayList;
import java.util.List;

/**
 * @author
 */
@Data
public class TreeNode {
//在本方法中需要用到的属性写上
   protected String id;
   protected String parentId;
   private Integer sort;
   protected List<TreeNode> children = new ArrayList<>();

   public void addChildren(TreeNode treeNode) {
      children.add(treeNode);
   }

   public List<TreeNode> getChildren() {
      if(children.size()<=0){
         return null;
      }
      return children;
   }
}

继承的类里面需要写上在这个方法中需要用到的属性,因为在该类中暂时类型还是泛型T,所以无法通过.get的方法来获取参数属性,继承类可以解决;

- 3:分层完成,返回前端页面即可;

需要多加分层只需要添加相应的元素,将父id指向已存在的id就行

进行举例子

具体问题

需要对部门进行分层级展示

数据库数据

在这里插入图片描述

对应的实体类

/**
 * 部门表
 * @author byChen
 * @date 2021/8/18
 */
@Data
@TableName("wx_depart")
public class WxDepart {
   /**
    * 主键id
    */
   @TableId(type = IdType.AUTO)
   private Integer id;
   /**
    *创建的部门id
    */
   private Long deptId;
   /**
    *部门名称
    */
   private String name;
   /**
    *英文名称
    */
   private String enName;
   /**
    *父部门id
    */
   private Long parentId;
   /**
    *在父部门中的次序值。order值大的排序靠前。值范围是[0, 2^32)
    */
   private Long departOrder;
   /**
    * 下级部门
    * 存储下级元素
    */
   @TableField(exist = false)
   private List<WxDepart> children;
}

具体代码


/**
 * 根据层级递归获取
 *
 * @return
 * @throws WxErrorException
 */
@RequestMapping(value = "/queryByLevel", method = RequestMethod.GET)
public R queryByLevel() throws WxErrorException {
   List<WxDepart> tree = new ArrayList<>();
   //所有部门
   List<WxDepart> list = wxDepartService.list();
   for (WxDepart wxDepart : list) {
      //当前部门id
      Long deptId = wxDepart.getDeptId();
      if (deptId == 0) {
         //底层树节点建立
         tree.add(wxDepart);
      }
      //再次遍历所有,找到当前部门的下级,并存入
      for (WxDepart wxDepart2 : list) {
         if (wxDepart2.getParentId().equals(wxDepart.getDeptId())) {
         //不能直接调用children,进行赋值,会报空指针
            List<WxDepart> list1 = new ArrayList<>();
            list1.add(wxDepart2);
            wxDepart.setChildren(list1);
         }
      }
   }
   return R.ok(list);
}

返回结果

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值