部门管理系统设计
题目要求
- 设计部门 MySQL 数据表
- 实现接口:根据中间部门 ID 获取其下属叶子部门 ID
- 设计包含子节点列表的 Java 数据对象,并实现批量获取功能
一、MySQL 部门表设计
表结构
CREATE TABLE department (id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '部门ID',name VARCHAR(100) NOT NULL COMMENT '部门名称',parent_id BIGINT COMMENT '父部门ID,顶级部门为NULL',is_leaf TINYINT(1) DEFAULT 0 COMMENT '是否为叶子部门:0-否,1-是',FOREIGN KEY (parent_id) REFERENCES department(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='部门表';
字段说明
id
: 主键,部门唯一标识name
: 部门名称parent_id
: 父部门关联IDis_leaf
: 叶子节点标识(可选)
优化建议
可选择动态计算叶子节点:
SELECT COUNT(*) FROM department WHERE parent_id = ?
二、获取叶子部门接口实现
简单的获取当前节点下的叶子节点:
SELECT d.id, d.name, d.is_leaf
FROM department d
WHERE d.parent_id = 2; -- 技术部的 id 是 2
递归查询方案,查询当前节点及其子节点下所有的叶子节点(MySQL 8.0+)
WITH RECURSIVE dept_tree AS (-- 基础查询:选出指定的几个部门(比如传入的中间部门 ids)SELECT id, parent_id, is_leafFROM departmentWHERE id IN (1) -- 🔹输入的部门ID,可以是中间部门或任意部门UNION ALL-- 递归查询:找出这些部门的子部门,再子部门的子部门...(无限层级往下遍历)SELECT d.id, d.parent_id, d.is_leafFROM department dJOIN dept_tree dt ON d.parent_id = dt.id
)
-- 最终查询:从递归结果中,筛选出 is_leaf = 1 的部门,即叶子节点
SELECT id
FROM dept_tree
WHERE is_leaf = 1;
三、Java 数据对象设计与批量获取功能实现
1. Java 数据对象设计(包含子节点列表)
我们设计一个 Department 类,用于表示部门信息,并包含其子部门列表,以支持树形结构的构建。
import java.util.ArrayList;
import java.util.List;/*** 部门实体类,包含子节点列表,用于构建部门树结构*/
public class Department {private Long id;private String name;private Long parentId;private Boolean isLeaf;private List<Department> children; // 子部门列表// 构造函数// Getter 和 Setter 方法public List<Department> getChildren() {return children;}public void setChildren(List<Department> children) {this.children = children;}// 添加子节点public void addChild(Department child) {this.children.add(child);}
}
2. 批量获取叶子部门 ID 的功能实现
我们提供一个服务类 DepartmentService,其中包含如下功能:
• 根据中间部门 ID 获取其下属所有叶子部门 ID
• 批量获取多个中间部门的叶子部门 ID
• 构建部门树(可选,用于前端展示等场景)
2.1 Service 接口定义
import java.util.List;public interface DepartmentService {/*** 根据中间部门ID,获取其下属所有叶子部门的ID列表* @param parentId 中间部门ID* @return 叶子部门ID集合*/List<Long> getLeafDepartmentIds(Long parentId);/*** 批量获取多个中间部门ID下属的所有叶子部门ID* @param parentIds 中间部门ID集合* @return Map<中间部门ID, 叶子部门ID列表>*/Map<Long, List<Long>> getLeafDepartmentIdsBatch(List<Long> parentIds);/*** 获取所有部门数据(用于构建树或递归查询,可从数据库加载)* @return 部门列表*/List<Department> getAllDepartments();/*** 构建部门树结构(可选功能,用于展示等)* @param departments 所有部门列表* @return 树形结构的部门列表(通常只有根节点或一级节点)*/List<Department> buildDepartmentTree(List<Department> departments);
}
2.2 Service 实现类
import org.springframework.stereotype.Service;import java.util.*;
import java.util.stream.Collectors;@Service
public class DepartmentServiceImpl implements DepartmentService {// 模拟从数据库中获取所有部门信息(实际应从数据库查询,比如使用JPA、MyBatis等)@Overridepublic List<Department> getAllDepartments() {// 这里模拟数据,实际应从数据库查询List<Department> departments = new ArrayList<>();departments.add(new Department(1L, "总公司", null, false));departments.add(new Department(2L, "技术部", 1L, false));departments.add(new Department(3L, "产品部", 1L, false));departments.add(new Department(4L, "前端组", 2L, true));departments.add(new Department(5L, "后端组", 2L, true));departments.add(new Department(6L, "UI组", 3L, true));departments.add(new Department(7L, "测试组", 2L, true));return departments;}/*** 获取指定父部门下所有叶子部门的ID*/@Overridepublic List<Long> getLeafDepartmentIds(Long parentId) {List<Department> allDepts = getAllDepartments();return findLeafIds(allDepts, parentId);}/*** 批量获取多个父部门下的所有叶子部门ID*/@Overridepublic Map<Long, List<Long>> getLeafDepartmentIdsBatch(List<Long> parentIds) {List<Department> allDepts = getAllDepartments();Map<Long, List<Long>> result = new HashMap<>();for (Long parentId : parentIds) {List<Long> leafIds = findLeafIds(allDepts, parentId);result.put(parentId, leafIds);}return result;}/*** 递归查找某个父部门下所有的叶子部门ID*/private List<Long> findLeafIds(List<Department> departments, Long parentId) {List<Long> leafIds = new ArrayList<>();// 找出直接子部门for (Department dept : departments) {if (Objects.equals(dept.getParentId(), parentId)) {if (dept.getIsLeaf() != null && dept.getIsLeaf()) {// 是叶子节点leafIds.add(dept.getId());} else {// 非叶子节点,递归查找leafIds.addAll(findLeafIds(departments, dept.getId()));}}}return leafIds;}/*** 构建部门树结构(可选,用于前端树形展示)*/@Overridepublic List<Department> buildDepartmentTree(List<Department> departments) {// 找出所有根节点(parent_id is null)List<Department> roots = departments.stream().filter(d -> d.getParentId() == null).collect(Collectors.toList());// 递归构建子节点for (Department root : roots) {buildChildren(root, departments);}return roots;}/*** 递归设置子节点*/private void buildChildren(Department parent, List<Department> allDepartments) {List<Department> children = allDepartments.stream().filter(d -> Objects.equals(d.getParentId(), parent.getId())).collect(Collectors.toList());for (Department child : children) {parent.addChild(child);buildChildren(child, allDepartments); // 递归查找子节点的子节点}}
}
3. 接口调用示例(Controller 示例,可选)
如果你使用 Spring Boot,可以提供一个 REST 接口来调用上述服务:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;
import java.util.Map;@RestController
@RequestMapping("/api/departments")
public class DepartmentController {@Autowiredprivate DepartmentService departmentService;/*** 获取某个部门下的所有叶子部门ID*/@GetMapping("/leaf-ids/{parentId}")public List<Long> getLeafIds(@PathVariable Long parentId) {return departmentService.getLeafDepartmentIds(parentId);}/*** 批量获取多个部门下的所有叶子部门ID*/@PostMapping("/leaf-ids/batch")public Map<Long, List<Long>> getLeafIdsBatch(@RequestBody List<Long> parentIds) {return departmentService.getLeafDepartmentIdsBatch(parentIds);}/*** 获取完整的部门树结构(可选)*/@GetMapping("/tree")public List<Department> getDepartmentTree() {List<Department> allDepts = departmentService.getAllDepartments();return departmentService.buildDepartmentTree(allDepts);}
}
四、总结
功能 实现内容
MySQL 表设计 包含 id、name、parent_id、is_leaf 字段,支持层级与叶子标识
递归查询叶子部门 SQL(MySQL 8.0+) 使用 WITH RECURSIVE 查询指定部门下所有叶子节点
Java 实体类 Department 类,包含子节点列表 children,支持树形结构
批量获取叶子部门ID Service 层提供根据父部门 ID(或批量)查询所有叶子部门 ID 的功能,支持递归查找
可选功能 构建完整的部门树结构,便于前端展示;提供 REST 接口调用
五、扩展建议
- 缓存优化:对于部门数据不频繁变动的场景,可使用 Redis 缓存部门树或叶子部门关系,提高查询效率。
- 数据库索引优化:为 parent_id 字段添加索引,加快查询速度。
- 动态 is_leaf:如果不想手动维护 is_leaf 字段,可通过查询是否有子部门来动态判断是否为叶子节点。
- 异步加载:对于大型部门树,可考虑懒加载/异步加载子节点,提升用户体验。
如你还需要 MyBatis 或 JPA 的具体实现、前端树形组件对接、递归性能优化等,可以继续提问!