树形菜单

  树形菜单应该是很常见的了,类似下面这种,通常我们的做法是后端从数据库中查询出来数据,然后将其转为树的结构,丢给前端,前端就渲染到树组件中;

 

  那么返给前端的数据是什么样的呢?如下所示

[    {
          id: 1,
          label: '一级 1',
          children: [{
            id: 4,
            label: '二级 1-1',
            children: [{
              id: 9,
              label: '三级 1-1-1'
            }, {
              id: 10,
              label: '三级 1-1-2'
            }]
          }]
        },
    {xxx}

]    

 

 

  那么对应在数据库中的表示什么样子的呢?Subject表下图所示,如果parent_id为0的,表示是一级菜单,其他多个二级菜单的parent_id等于某个一级菜单的id,依次类推,可有有很多级别菜单

 

 

下面用java代码实现

  1.工具类:

package com.protagonist.edu.utils;

import com.protagonist.edu.bo.SubjectTreeNodeBO;
import com.protagonist.edu.entity.Subject;
import com.protagonist.responseVO.StatusCode;
import com.protagonist.servicebase.exception.ProtagonistException;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * 用于构建树形结构
 */
public class TreeUtil {
    /**
     * 默认树形菜单最顶层的pid是"0"
     * @param list 所有数据
     * @return 树形的数据
     */
    public static  List<SubjectTreeNodeBO> buildTree(List<Subject> list) {
        if (CollectionUtils.isEmpty(list)){
            throw new ProtagonistException(StatusCode.ERROR,"查询的菜单数据为空,不能转为树形");
        }
        return buildTree(list, "0");
    }

    /**
     *   获取树形菜单结构
     *      思路:首先遍历一次将所有的数据转化为前端需要的数据类型,然后放入到map中,以id->T对应关系
     *      然后再遍历一次,这次的话判断parentId是否为0(这里暂时可以特使pid为0时表示一级菜单),是的话就是一级菜单,就放到rootTree中;
     *      不为0的话,说明不是一级菜单,我们就需要获取它的父菜单
     *      根据pid去map中获取,然后将当前菜单放入其父菜单的子菜单中,等遍历完之后树形菜单就ok了,这种做法可以完成多级子菜单变成树形
     * @param list 所有的数据
     * @param pid 父id
     * @return 树形数据
     */
    public static  List<SubjectTreeNodeBO> buildTree(List<Subject> list, String pid) {
        if (CollectionUtils.isEmpty(list)){
            throw new ProtagonistException(StatusCode.ERROR,"查询的菜单数据为空,不能转为树形");
        }
        List<SubjectTreeNodeBO> allTreeNode = new ArrayList<>();
        List<SubjectTreeNodeBO> rootTree = new ArrayList<>();
        Map<String, SubjectTreeNodeBO> nodeMap = new HashMap<>();
        //将所有的数据都放入到map中一份
        for (Subject item : list) {
            SubjectTreeNodeBO nodeBO = new SubjectTreeNodeBO();
            BeanUtils.copyProperties(item,nodeBO);
            allTreeNode.add(nodeBO);
            nodeMap.put(item.getId(),nodeBO);
        }
        for (SubjectTreeNodeBO t : allTreeNode) {
            //如果父id等于传进来的pid,那么该菜单是最顶级的菜单,放入到rootTree中
            if (Objects.equals(t.getParentId(), pid)){
                rootTree.add(t);
                //如果不是顶级菜单,那就获取父菜单,然后嫁给你本BO设置到父菜单的children中
            }else {
                SubjectTreeNodeBO parentNode = nodeMap.get(t.getParentId());
                parentNode.getChildren().add(t);
            }
        }
        return rootTree;
    }
}

 

   2.subject类:

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("subject")
@ApiModel(value="Subject对象", description="课程科目")
public class Subject implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "课程类别ID")
    @TableId(value = "id", type = IdType.ID_WORKER_STR)
    private String id;

    @ApiModelProperty(value = "类别名称")
    private String title;

    @ApiModelProperty(value = "父ID")
    private String parentId;

}

 

3.SubjectTreeNodeBO类:
package com.protagonist.edu.bo;

import lombok.Data;

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

@Data
public class SubjectTreeNodeBO {

    private String id;

    private String title;

    private String parentId;

    private List<SubjectTreeNodeBO> children = new ArrayList<>();
}

 

  4. 测试,成功,然后配合element的Tree 树形控件一起使用,就行了

 

posted @ 2020-10-04 11:04  java小新人  阅读(1676)  评论(0编辑  收藏  举报