最近写公司项目的时候,后台的角色权限和部门管理、或者菜单管理总会碰到多级菜单或者树,公司同事有不太明白中间逻辑的,于是便有了本文和大家一起分享实现思路及案例
首先是数据库的建立,我这里是单表中添加了一个字段来保存父节点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);
建好的表如下图
然后使用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 children;
然后在控制层Controller中编写调用的方法
/**
* 部门控制层
*
* @author az
* @since 2021-11-24
*/
@RestController
@RequestMapping("/dept")
public class DeptController {
@Resource
private DeptService deptService;
@GetMapping("/deptTree")
public List deptTree(){
return deptService.getDeptTree();
}
}
接下来是业务层Service
/**
* 部门业务层
*
* @author az
* @since 2021-11-24
*/
public interface DeptService extends IService {
/**
* 获取部门树
* @return 部门树
*/
List getDeptTree();
}
最后在业务实现层ServiceImpl里写具体的功能实现
/**
* 部门业务实现层
*
* @author az
* @since 2021-11-24
*/
@Service
public class DeptServiceImpl extends ServiceImpl implements DeptService {
@Resource
private DeptMapper deptMapper;
@Override
public List getDeptTree() {
//获取所有部门
List allDept = deptMapper.selectList(null);
//用来保存父节点
List rootDept = new ArrayList<>();
//用来保存子节点
List 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 getChildren(Integer id, List allDept){
//存放子节点
List 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;
}
}
工具类里有行代码写的是自调用,意思是如果有子节点继续往下套,这样写的好处就是不限层级,无论有多少级都可以被嵌套进去
最后我们启动,为了方便演示我这里使用浏览器进行访问
成功实现多级树,以上!