如何在 Spring Boot 中设计和返回树形结构的组织和部门信息
如何在 Spring Boot 中设计和返回树形结构的组织和部门信息
文章目录
- 如何在 Spring Boot 中设计和返回树形结构的组织和部门信息
- 1. 需求分析
- 一、数据库表设计
- 1.1 `organization` 表设计
- 1.2 `department` 表设计
- 1.3 模拟数据
- 二、后端设计
- 2.1 实体类设计
- `Organization` 实体类
- `Department` 实体类
- 2.2 DTO 类设计
- `OrganizationDTO`
- `DepartmentDTO`
- 2.3 Service 层设计
- 2.4 Controller 层设计
- 三、前端请求与展示
- 总结
在企业管理系统中,组织和部门之间通常存在层级结构,每个组织和部门都可能有多个子级和父级。这种树形结构的数据管理在很多业务场景下都十分常见,比如权限控制、员工管理等。
今天我们将深入探讨如何在 Spring Boot 中设计组织和部门表,如何在后端生成并返回树形结构数据,以及如何展示组织和部门的完整信息。
1. 需求分析
我们需要设计两个表:组织表(organizations
)和部门表(departments
)。两张表之间存在如下关系:
- 每个组织可以有一个父组织,也可以有多个子组织,形成树形结构。
- 每个部门属于某个组织,并且每个部门也有可能有子部门,部门之间同样需要支持树形结构。
- 前端需要通过接口获取组织和部门的树形结构数据,后端通过递归算法构建树形层级。
一、数据库表设计
首先,我们需要设计两张表:organization
和 department
。organization
表用于存储组织的信息,department
表用于存储部门的信息。两张表都需要支持树形结构的关系。
1.1 organization
表设计
organization
表用于存储组织的基本信息,并支持组织的树形层级关系。- 每个组织可以有一个父组织,也可以有多个子组织。
- 通过
parent_id
字段,我们可以表示组织之间的父子关系。
CREATE TABLE `organization` (`id` BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '组织ID',`name` VARCHAR(255) NOT NULL COMMENT '组织名称',`description` VARCHAR(255) COMMENT '组织描述',`location` VARCHAR(255) COMMENT '组织位置',`parent_id` BIGINT DEFAULT NULL COMMENT '父组织ID',`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',CONSTRAINT `fk_parent_org` FOREIGN KEY (`parent_id`) REFERENCES `organization` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
1.2 department
表设计
department
表用于存储部门信息,支持部门的树形层级关系。每个部门也可以有一个父部门,也可以有多个子部门。- 同时,每个部门属于一个组织, 部门关联到一个组织。
organization_id
是部门所属的组织。parent_id
是部门的父级部门。
CREATE TABLE `department` (`id` BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '部门ID',`name` VARCHAR(255) NOT NULL COMMENT '部门名称',`description` VARCHAR(255) COMMENT '部门描述',`employee_count` INT DEFAULT 0 COMMENT '员工数量',`organization_id` BIGINT NOT NULL COMMENT '所属组织ID',`parent_id` BIGINT DEFAULT NULL COMMENT '父部门ID',`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',CONSTRAINT `fk_org_id` FOREIGN KEY (`organization_id`) REFERENCES `organization` (`id`) ON DELETE CASCADE,CONSTRAINT `fk_parent_dep` FOREIGN KEY (`parent_id`) REFERENCES `department` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
1.3 模拟数据
接下来我们可以插入一些模拟数据,以便于我们在后续实现中测试树形结构。
-- 插入组织数据
INSERT INTO `organization` (`name`, `description`, `location`,`parent_id`) VALUES
('总公司', '总部组织', '上海', NULL);
('分公司A', '分公司A', '北京', 1);
('分公司B', '分公司B', '深圳', 1);
('分公司C', '分公司C', '杭州', 2);-- 插入部门数据
INSERT INTO `department` (`name`, `description`, `employee_count`, `organization_id`, `parent_id`) VALUES
('总部', '总部部门', 20, 1, NULL),
('人事部', '管理人力资源', 5, 1, 1),
('IT部', '技术支持部门', 10, 1, 1),
('市场部', '市场推广部门', 5, 1, 1),
('分公司A', '分公司A部门', 30, 2, NULL),
('市场部A', '市场部A', 5, 2, 5);
二、后端设计
2.1 实体类设计
在 Spring Boot 中,我们需要根据数据库表设计对应的实体类。
Organization
实体类
import javax.persistence.*;
import java.util.List;@Entity
public class Organization {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;private String description;private String location;@ManyToOne@JoinColumn(name = "parent_id")private Organization parent;@OneToMany(mappedBy = "parent")private List<Organization> children;@OneToMany(mappedBy = "organization")private List<Department> departments;private String createdAt;private String updatedAt;// Getters and setters
}
Department
实体类
import javax.persistence.*;
import java.util.List;@Entity
public class Department {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;private String description;private Integer employeeCount;@ManyToOne@JoinColumn(name = "organization_id")private Organization organization;@ManyToOne@JoinColumn(name = "parent_id")private Department parent;@OneToMany(mappedBy = "parent")private List<Department> children;private String createdAt;private String updatedAt;// Getters and setters
}
2.2 DTO 类设计
为了控制返回数据,我们使用 DTO(数据传输对象)来传递组织和部门的完整信息。
OrganizationDTO
import java.util.List;public class OrganizationDTO {private Long id;private String name;private String description;private String location;private String createdAt;private String updatedAt;private List<DepartmentDTO> departments;private List<OrganizationDTO> children;private OrganizationDetails details;public static class OrganizationDetails {private Long id;private String name;private String description;private String location;private String createdAt;private String updatedAt;}// Getters and setters
}
DepartmentDTO
import java.util.List;public class DepartmentDTO {private Long id;private String name;private String description;private Integer employeeCount;private String createdAt;private String updatedAt;private List<DepartmentDTO> children;private DepartmentDetails details;public static class DepartmentDetails {private Long id;private String name;private String description;private Integer employeeCount;private String createdAt;private String updatedAt;}// Getters and setters
}
2.3 Service 层设计
在 Service 层中,我们将组织和部门信息转换为树形结构,并填充每个节点的详细信息。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.stream.Collectors;@Service
public class OrganizationService {@Autowiredprivate OrganizationRepository organizationRepository;@Autowiredprivate DepartmentRepository departmentRepository;// 获取组织树形结构public List<OrganizationDTO> getOrganizationTree() {List<Organization> rootOrganizations = organizationRepository.findByParentIsNull();return rootOrganizations.stream().map(this::convertToOrganizationDTO).collect(Collectors.toList());}// 转换组织实体为组织DTOprivate OrganizationDTO convertToOrganizationDTO(Organization org) {OrganizationDTO orgDTO = new OrganizationDTO();orgDTO.setId(org.getId());orgDTO.setName(org.getName());orgDTO.setDescription(org.getDescription());orgDTO.setLocation(org.getLocation());orgDTO.setCreatedAt(org.getCreatedAt());orgDTO.setUpdatedAt(org.getUpdatedAt());// 填充子组织List<OrganizationDTO> children = org.getChildren().stream().map(this::convertToOrganizationDTO).collect(Collectors.toList());orgDTO.setChildren(children);// 填充部门树List<DepartmentDTO> departments = org.getDepartments().stream().map(this::convertToDepartmentDTO).collect(Collectors.toList());orgDTO.setDepartments(departments);// 填充详细信息OrganizationDTO.OrganizationDetails details = new OrganizationDTO.OrganizationDetails();details.setId(org.getId());details.setName(org.getName());details.setDescription(org.getDescription());details.setLocation(org.getLocation());details.setCreatedAt(org.getCreatedAt());details.setUpdatedAt(org.getUpdatedAt());orgDTO.setDetails(details);return orgDTO;}// 转换部门实体为部门DTOprivate DepartmentDTO convertToDepartmentDTO(Department dep) {DepartmentDTO depDTO = new DepartmentDTO();depDTO.setId(dep.getId());depDTO.setName(dep.getName());depDTO.setDescription(dep.getDescription());depDTO.setEmployeeCount(dep.getEmployeeCount());depDTO.setCreatedAt(dep.getCreatedAt());depDTO.setUpdatedAt(dep.getUpdatedAt());// 填充子部门List<DepartmentDTO> children = dep.getChildren().stream().map(this::convertToDepartmentDTO).collect(Collectors.toList());depDTO.setChildren(children);// 填充详细信息DepartmentDTO.DepartmentDetails details = new DepartmentDTO.DepartmentDetails();details.setId(dep.getId());details.setName(dep.getName());details.setDescription(dep.getDescription());details.setEmployeeCount(dep.getEmployeeCount());details.setCreatedAt(dep.getCreatedAt());details.setUpdatedAt(dep.getUpdatedAt());depDTO.setDetails(details);return depDTO;}
}
2.4 Controller 层设计
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
@RequestMapping("/api/organizations")
public class OrganizationController {@Autowiredprivate OrganizationService organizationService;@GetMapping("/tree")public List<OrganizationDTO> getOrganizationTree() {return organizationService.getOrganizationTree();}
}
三、前端请求与展示
前端通过 GET /api/organizations/tree
请求接口,返回数据结构如下(嵌套完整组织部门信息):
[{"id": 1,"name": "总公司","description": "总部组织","location": "上海","createdAt": "2023-01-01T10:00:00","updatedAt": "2023-10-01T10:00:00","children": [{"id": 2,"name": "分公司A","description": "分公司A","location": "北京","createdAt": "2023-01-05T12:00:00","updatedAt": "2023-10-01T12:00:00","children": [],"departments": [{"id": 4,"name": "IT部","description": "技术支持部门","employeeCount": 10,"createdAt": "2023-01-10T09:00:00","updatedAt": "2023-10-01T09:00:00","children": [],"details": {"id": 4,"name": "IT部","description": "技术支持部门","employeeCount": 10,"createdAt": "2023-01-10T09:00:00","updatedAt": "2023-10-01T09:00:00"}}]}],"departments": [{"id": 1,"name": "总部","description": "总部部门","employeeCount": 20,"createdAt": "2023-01-01T10:00:00","updatedAt": "2023-10-01T10:00:00","children": [],"details": {"id": 1,"name": "总部","description": "总部部门","employeeCount": 20,"createdAt": "2023-01-01T10:00:00","updatedAt": "2023-10-01T10:00:00"}}]}
]
总结
在本文中,我们介绍了如何在 Spring Boot 中设计组织和部门表,如何处理树形结构,并通过 DTO 设计将组织和部门的完整信息传递给前端。在后端,我们使用了递归方法来构建树形数据结构,确保每个节点都包含该组织或部门的详细信息。