最近遇到了一个分层级展示指标的需求,前端使用el-tree树形组件,要求按官方文档的格式提供数据。

数据格式:

data: [{
          id: 1,
          label: '一级 1',
          children: [{
            id: 4,
            label: '二级 1-1',
            children: [{
              id: 9,
              label: '三级 1-1-1'
            }, {
              id: 10,
              label: '三级 1-1-2'
            }]
          }]
        }, {
          id: 2,
          label: '一级 2',
          children: [{
            id: 5,
            label: '二级 2-1'
          }, {
            id: 6,
            label: '二级 2-2'
          }]
        }, {
          id: 3,
          label: '一级 3',
          children: [{
            id: 7,
            label: '二级 3-1'
          }, {
            id: 8,
            label: '二级 3-2'
          }]
        }]

封装思路

1、首先我们需要获取到所有的节点,新建一个集合result来保存所有顶级节点,也就是parentId为空的或指定值。

2、然后我们需要找出二级节点存入到顶级节点的childList中,找到三级节点存入到二级节点的childList中,依次类推,最后将result返回。

代码实现:

1、设计实体类
@Data
public class Evaluation {
    private String id;
    private String label;
    private String parentId;
    private List<Evaluation> childList;
}
2、业务代码
public class EvaluationService {

    private EvaluationDao evaluationDao;
​
    public List<Evaluation> getEvaluations() {
        // 查出所有指标
        List<Evaluation> all = evaluationDao.findAll();

        // 把所有的数据都放到map中
        Map<String, Evaluation> treeMap = new HashMap<>();
        for (int i = 0; i < all.size() && !all.isEmpty(); i++) {
            // 元素的id为键,元素本身为值
            treeMap.put(all.get(i).getId(), all.get(i));
        }

        // 将所有顶层节点存入result中
        List<Evaluation> result = new ArrayList<>();
        // 遍历map得到顶层节点或者游离节点
        for (int i = 0; i < all.size(); i++) {
            if (!treeMap.containsKey(all.get(i).getParentId())) {
                result.add(all.get(i));
            }
        }
​
        // 遍历数据,将对象放入父级节点的childList属性中
        for (int i = 0; i < all.size() && !all.isEmpty(); i++) {
            Evaluation Evaluation = treeMap.get(all.get(i).getParentId());
            if (Evaluation != null) {
                // 有父节点,校验父节点下childList是否存在,然后将子节点放入
                if (Evaluation.getChildList() == null) {
                    Evaluation.setChildList(new ArrayList<>());
                }
                // 添加到父节点的ChildList集合下
                Evaluation.getChildList().add(all.get(i));
            }
        }
        return result;
    }
}

如果项目中使用的不多的话,这样就可以了。实现方式可以有很多种,用上边的方式的好处在于免去了多次到数据库查询的操作,而且可以灵活封装多层级数据,二层、三层、五层等等都可以。

工具类

为了实现代码的复用,我们可以将上方代码封装成工具类。

DataTree接口:

写这个接口类主要是为了下面的工具类,定义泛型T的类型

public interface DataTree<T> {
​
    public String getId();
​
    public String getParentId();
​
    public void setChildList(List<T> childList);
​
    public List<T> getChildList();
}
工具类实现:

以下的泛型T就是接收数据的实体类,要继承上面数据接口类

public class TreeUtils {
​
    //获取顶层节点
    public static <T extends DataTree<T>> List<T> getTreeList(String topId, List<T> entityList) {

        List<T> resultList = new ArrayList<>();
​
        Map<Object, T> treeMap = new HashMap<>();
​
        T itemTree;
​
        for (int i = 0; i < entityList.size() && !entityList.isEmpty(); i++) {
            itemTree = entityList.get(i);
            //把所有的数据放到treeMap中,id为key
            treeMap.put(itemTree.getId(), itemTree);
            //把顶层节点放到集合resultList中
            if (topId.equals(itemTree.getParentId()) || itemTree.getParentId() == null) {
                resultList.add(itemTree);
            }
        }
​
        //循环数据,把数据放到上一级的childen属性中
        for (int i = 0; i < entityList.size() && !entityList.isEmpty(); i++) {
            itemTree = entityList.get(i);
            T data = treeMap.get(itemTree.getParentId());
            // 不等于null,也就意味着有父节点
            if (data != null) {
                if (data.getChildList() == null) {
                    data.setChildList(new ArrayList<>());
                }
                //把子节点 放到父节点childList当中
                data.getChildList().add(itemTree);
                //把放好的数据放回map当中
                treeMap.put(itemTree.getParentId(), data);
            }
        }
        return resultList;
    }
}
使用方式:

1、实体类:

设计实体类,实现之前定义好的DataTree接口

@Data
public class Evaluation implements DataTree<Evaluation> {
​
    private String id;
​
    private String label;
​
    private String parentId;
​
    private List<Evaluation> childList;
}

2、调用TreeUtils,传入数据和顶层节点id,即可获取到所需要的数据结构。

public class Test {
    private EvaluationDao evaluationDao;
​
    public List<Evaluation> getEvaluations() {
​
        // 接收在数据库中查询到的数据
        List<Evaluation> data = evaluationDao.findAll();
​
        // 调用工具类,第一个参数是默认传入的顶级id,和查询出来的数据
        return TreeUtils.getTreeList("0", data);
    }
}

参考博客: https://blog.csdn.net/qq_36956154/article/details/79893876

12-31 23:58
查看更多