三层目录建树

关键思想:

  • 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就行
上一篇:(六)动态规划【C++刷题】


下一篇:1051. 高度检查器