最近写公司项目的时候,后台的角色权限和部门管理、或者菜单管理总会碰到多级菜单或者树,公司同事有不太明白中间逻辑的,于是便有了本文和大家一起分享实现思路及案例

首先是数据库的建立,我这里是单表中添加了一个字段来保存父节点id

CREATE TABLE `dept`  (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '部门id',
  `dept_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '部门名称',
  `dept_code` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '部门编码',
  `parent_id` int NULL DEFAULT NULL COMMENT '父部门id',
  `remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;


## 插入测试数据
INSERT INTO `dept` VALUES (1, 'A公司', 'A123', 0, '公司A');
INSERT INTO `dept` VALUES (2, 'B公司', 'B123', 0, '公司B');
INSERT INTO `dept` VALUES (3, '人事部', 'A425', 1, NULL);
INSERT INTO `dept` VALUES (4, '技术部', 'A389', 1, NULL);
INSERT INTO `dept` VALUES (5, '销售部', 'A527', 1, NULL);
INSERT INTO `dept` VALUES (6, '后勤部', 'B522', 2, NULL);
INSERT INTO `dept` VALUES (7, '财务组', 'A451', 3, NULL);
INSERT INTO `dept` VALUES (8, '前端组', 'A562', 4, NULL);
INSERT INTO `dept` VALUES (9, '后端组', 'A963', 4, NULL);
INSERT INTO `dept` VALUES (10, 'xx项目组', 'A752', 9, NULL);

建好的表如下图

java简单实现多级菜单 java递归多级菜单_idea

java简单实现多级菜单 java递归多级菜单_java_02

然后使用Mybatis-Plus的代码生成去生成我们需要的代码

然后在生成好的实体类里加一个list集合,这里是为了存放子节点用的,数据库中不存在

/**
 * 部门实体类
 *
 * @author az
 * @since 2021-11-24
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("dept")
public class Dept implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 部门id
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    /**
     * 部门名称
     */
    private String deptName;

    /**
     * 部门编码
     */
    private String deptCode;

    /**
     * 父部门id
     */
    private Integer parentId;

    /**
     * 备注
     */
    private String remark;

    /**
     * 子节点
     */
    @TableField(exist = false)
    private List<Dept> children;

然后在控制层Controller中编写调用的方法

/**
 * 部门控制层
 *
 * @author az
 * @since 2021-11-24
 */
@RestController
@RequestMapping("/dept")
public class DeptController {

    @Resource
    private DeptService deptService;

    @GetMapping("/deptTree")
    public List<Dept> deptTree(){
        return deptService.getDeptTree();
    }

}

接下来是业务层Service

/**
 * 部门业务层
 *
 * @author az
 * @since 2021-11-24
 */
public interface DeptService extends IService<Dept> {

    /**
     * 获取部门树
     * @return 部门树
     */
    List<Dept> getDeptTree();
}

最后在业务实现层ServiceImpl里写具体的功能实现

/**
 * 部门业务实现层
 *
 * @author az
 * @since 2021-11-24
 */
@Service
public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements DeptService {

    @Resource
    private DeptMapper deptMapper;

    @Override
    public List<Dept> getDeptTree() {
        //获取所有部门
        List<Dept> allDept = deptMapper.selectList(null);
        //用来保存父节点
        List<Dept> rootDept = new ArrayList<>();
        //用来保存子节点
        List<Dept> childList = new ArrayList<>();
        //遍历所有部门,将所有部门的父部门id为0的部门放入父节点集合中
        for (Dept dept : allDept) {
            Integer parentId = dept.getParentId();
            if (parentId == 0) {
                rootDept.add(dept);
            }
        }
        for (Dept dept : rootDept) {
            Integer deptId = dept.getId();
            //调用工具类获取子节点
            childList = GetChildrenUtils.getChildren(deptId,allDept);
            dept.setChildren(childList);
        }
        return rootDept;
    }
}

最后是工具类

/**
 * 获取子节点工具类
 *
 * @author az
 * @date 2021/11/24 0024
 */
public class GetChildrenUtils {

    public static List<Dept> getChildren(Integer id, List<Dept> allDept){
        //存放子节点
        List<Dept> childList = new ArrayList<>();
        //遍历所有部门,如果部门的父部门id与传来的id相同,则为传来的id这个部门的子部门
        for (Dept dept : allDept) {
            Integer parentId = dept.getParentId();
            if (parentId.equals(id)) {
                childList.add(dept);
            }
        }

        //自调用来判断是否还有子节点
        for (Dept dept : childList) {
            dept.setChildren(getChildren(dept.getId(),allDept));
        }

        //如果没有子节点则返回空集合
        if (childList.size() == 0){
            return new ArrayList<>();
        }
        return childList;
    }
}

工具类里有行代码写的是自调用,意思是如果有子节点继续往下套,这样写的好处就是不限层级,无论有多少级都可以被嵌套进去

最后我们启动,为了方便演示我这里使用浏览器进行访问

java简单实现多级菜单 java递归多级菜单_spring boot_03

 成功实现多级树,以上!