You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

350 lines
17 KiB

1 month ago
# 部门管理
<cite>
**本文引用的文件**
- [SysDept.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysDept.java)
- [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java)
- [ISysDeptService.java](file://crm-auth/src/main/java/com/crm/auth/service/ISysDeptService.java)
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
- [DataInitializer.java](file://crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java)
- [application.yml](file://crm-auth/src/main/resources/application.yml)
- [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java)
- [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java)
- [TreeUtils.java](file://crm-base/src/main/java/com/crm/base/utils/TreeUtils.java)
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
- [SysDeptServiceImplTest.java](file://crm-auth/src/test/java/com/crm/auth/service/impl/SysDeptServiceImplTest.java)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录:API接口与使用案例](#附录api接口与使用案例)
## 简介
本技术文档聚焦于“部门管理”模块,围绕部门树形结构的设计与实现、CRUD操作、层级关系管理、缓存机制、数据初始化与同步、异常处理等进行系统化阐述。该模块基于 MyBatis-Plus 进行数据访问,通过 Redis 缓存提升部门树查询性能,并在服务层提供统一的树构建与层级维护能力,为权限控制、数据范围等上层功能提供基础支撑。
## 项目结构
部门管理相关代码主要分布在 crm-auth 模块中,实体定义在 domain.entity,数据访问在 mapper,业务逻辑在 service.impl,缓存与配置在 service 和 config 包下;通用基类与工具位于 crm-base 模块。
```mermaid
graph TB
subgraph "crm-auth"
A["entity: SysDept"] --> B["mapper: SysDeptMapper"]
B --> C["service: ISysDeptService"]
C --> D["service.impl: SysDeptServiceImpl"]
D --> E["service: DeptTreeCache"]
F["config: DataInitializer"] --> D
G["resources: application.yml"] --> E
end
subgraph "crm-base"
H["domain.entity: BaseEntity"] --> A
I["domain.entity: OwnedEntity"] --> A
J["utils: TreeUtils"] --> D
K["config: RedisConfig"] --> E
end
```
图表来源
- [SysDept.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysDept.java)
- [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java)
- [ISysDeptService.java](file://crm-auth/src/main/java/com/crm/auth/service/ISysDeptService.java)
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
- [DataInitializer.java](file://crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java)
- [application.yml](file://crm-auth/src/main/resources/application.yml)
- [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java)
- [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java)
- [TreeUtils.java](file://crm-base/src/main/java/com/crm/base/utils/TreeUtils.java)
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
章节来源
- [SysDept.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysDept.java)
- [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java)
- [ISysDeptService.java](file://crm-auth/src/main/java/com/crm/auth/service/ISysDeptService.java)
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
- [DataInitializer.java](file://crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java)
- [application.yml](file://crm-auth/src/main/resources/application.yml)
- [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java)
- [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java)
- [TreeUtils.java](file://crm-base/src/main/java/com/crm/base/utils/TreeUtils.java)
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
## 核心组件
- 实体模型:部门实体继承通用基类,包含父部门、排序、状态等字段,用于表达层级关系与生命周期。
- 数据访问:MyBatis-Plus Mapper 提供基础 CRUD 与条件查询能力。
- 服务层:统一封装部门增删改查、树构建、层级校验、缓存刷新等操作。
- 缓存层:基于 Redis 的部门树缓存,支持按维度(如租户或全局)存储与失效策略。
- 初始化器:应用启动时按需初始化默认部门数据,保证系统可用。
- 工具类:树构建工具提供将扁平列表组装为树结构的通用方法。
章节来源
- [SysDept.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysDept.java)
- [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java)
- [ISysDeptService.java](file://crm-auth/src/main/java/com/crm/auth/service/ISysDeptService.java)
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
- [DataInitializer.java](file://crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java)
- [TreeUtils.java](file://crm-base/src/main/java/com/crm/base/utils/TreeUtils.java)
## 架构总览
部门管理采用分层架构:Controller(如有)调用 Service,Service 组合 Mapper 与 Cache,Cache 基于 Redis 持久化树结构。数据初始化由独立任务在启动阶段执行,确保基础数据就绪。
```mermaid
sequenceDiagram
participant Client as "客户端"
participant Service as "ISysDeptService"
participant Impl as "SysDeptServiceImpl"
participant Mapper as "SysDeptMapper"
participant Cache as "DeptTreeCache"
participant Redis as "Redis"
Client->>Service : "获取部门树"
Service->>Impl : "getDeptTree()"
Impl->>Cache : "getTree(key)"
alt "缓存命中"
Cache-->>Impl : "返回树结构"
else "缓存未命中"
Impl->>Mapper : "selectList(全部/条件)"
Mapper-->>Impl : "扁平列表"
Impl->>Impl : "构建父子关系树"
Impl->>Cache : "putTree(key, tree)"
Cache->>Redis : "序列化并存储"
Redis-->>Cache : "OK"
end
Impl-->>Service : "树结果"
Service-->>Client : "返回树"
```
图表来源
- [ISysDeptService.java](file://crm-auth/src/main/java/com/crm/auth/service/ISysDeptService.java)
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
- [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java)
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
## 详细组件分析
### 实体模型设计
- 继承体系:部门实体继承 BaseEntity(通用审计字段)与 OwnedEntity(数据归属),便于统一时间戳、创建人、更新人及数据可见性控制。
- 层级字段:包含父部门标识、排序号、状态等,支撑树形结构与展示顺序。
- 约束与校验:建议在新增/修改时校验父部门存在性与循环引用,避免形成环状结构。
```mermaid
classDiagram
class BaseEntity {
+id
+createTime
+updateTime
+createBy
+updateBy
}
class OwnedEntity {
+ownerId
+dataScope
}
class SysDept {
+parentId
+sort
+status
+name
+code
+level
+path
}
BaseEntity <|-- SysDept
OwnedEntity <|-- SysDept
```
图表来源
- [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java)
- [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java)
- [SysDept.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysDept.java)
章节来源
- [SysDept.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysDept.java)
- [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java)
- [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java)
### 数据访问层(Mapper)
- 职责:提供基础的增删改查与条件查询能力,配合 MyBatis-Plus 简化 SQL 编写。
- 典型操作:根据父ID查询子节点、按状态过滤、批量更新排序等。
- 扩展点:可结合分页插件与自定义 SQL 注入器增强查询能力。
章节来源
- [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java)
### 服务层(Service)
- 接口定义:ISysDeptService 声明部门树构建、CRUD、层级校验、缓存刷新等能力。
- 实现要点:
- 树构建:从数据库拉取扁平列表,利用 TreeUtils 组装为树结构。
- 层级校验:防止自引用与循环引用,维护 level/path 等辅助字段。
- 事务控制:对多步写操作加事务,保证一致性。
- 缓存联动:写操作后主动失效或重建对应维度的树缓存。
```mermaid
flowchart TD
Start(["开始"]) --> CheckParent["校验父部门是否存在"]
CheckParent --> ParentExists{"父部门有效?"}
ParentExists --> |否| ThrowError["抛出参数异常"]
ParentExists --> |是| BuildPath["计算层级与路径"]
BuildPath --> SaveDB["保存/更新到数据库"]
SaveDB --> InvalidateCache["失效/重建缓存"]
InvalidateCache --> End(["结束"])
ThrowError --> End
```
图表来源
- [ISysDeptService.java](file://crm-auth/src/main/java/com/crm/auth/service/ISysDeptService.java)
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
- [TreeUtils.java](file://crm-base/src/main/java/com/crm/base/utils/TreeUtils.java)
章节来源
- [ISysDeptService.java](file://crm-auth/src/main/java/com/crm/auth/service/ISysDeptService.java)
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
- [TreeUtils.java](file://crm-base/src/main/java/com/crm/base/utils/TreeUtils.java)
### 缓存层(DeptTreeCache)
- 设计目标:降低高频树查询对数据库的压力,提升响应速度。
- 存储键策略:按维度(如租户ID或全局)作为 key,避免跨租户污染。
- 数据结构:序列化后的树对象,支持快速反序列化为前端可用的嵌套结构。
- 失效策略:
- 写操作后主动失效对应 key。
- 可选定时全量重建,保障极端场景下的数据一致性。
- 并发安全:读写分离与本地锁(如适用)避免缓存击穿。
```mermaid
classDiagram
class DeptTreeCache {
+getTree(key) Object
+putTree(key, tree) void
+invalidate(key) void
-serialize(obj) byte[]
-deserialize(bytes) Object
}
class RedisTemplate {
+opsForValue() ValueOperations
+expire(key, ttl) boolean
}
DeptTreeCache --> RedisTemplate : "存取与过期"
```
图表来源
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
章节来源
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
### 数据初始化(DataInitializer)
- 触发时机:应用启动阶段,检查是否已存在基础部门数据。
- 初始化内容:创建根部门、默认一级部门等,确保权限与数据范围可用。
- 幂等性:通过唯一编码或名称判断,避免重复初始化。
- 失败处理:记录日志并允许后续重试,不影响主流程启动。
章节来源
- [DataInitializer.java](file://crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java)
### 配置(application.yml)
- 关键项:Redis 连接信息、缓存 TTL、初始化开关等。
- 建议:生产环境开启连接池与超时配置,合理设置缓存过期时间。
章节来源
- [application.yml](file://crm-auth/src/main/resources/application.yml)
## 依赖关系分析
- 低耦合:Service 通过接口与 Mapper/Cache 解耦,便于替换实现与测试。
- 内聚性:树构建与层级校验集中在 Service 层,避免分散逻辑。
- 外部依赖:Redis 作为缓存后端,需保证高可用与容量规划。
```mermaid
graph LR
ISysDeptService --> SysDeptServiceImpl
SysDeptServiceImpl --> SysDeptMapper
SysDeptServiceImpl --> DeptTreeCache
DeptTreeCache --> RedisConfig
DataInitializer --> SysDeptServiceImpl
```
图表来源
- [ISysDeptService.java](file://crm-auth/src/main/java/com/crm/auth/service/ISysDeptService.java)
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
- [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java)
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
- [DataInitializer.java](file://crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java)
章节来源
- [ISysDeptService.java](file://crm-auth/src/main/java/com/crm/auth/service/ISysDeptService.java)
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
- [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java)
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
- [DataInitializer.java](file://crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java)
## 性能考虑
- 缓存命中率:热点部门树应优先命中缓存,减少 DB 压力。
- 序列化开销:树结构较大时,注意序列化格式与压缩策略。
- 失效粒度:按维度失效,避免全量重建带来的抖动。
- 查询优化:仅加载必要字段,必要时分页或懒加载子节点。
- 连接池:Redis 连接池大小与超时配置需匹配峰值 QPS。
[本节为通用指导,不直接分析具体文件]
## 故障排查指南
- 缓存不一致:检查写操作后是否及时失效 key,确认 TTL 与重建策略。
- 循环引用:校验父部门与子节点关系,避免形成环。
- 初始化失败:查看启动日志,确认唯一性判断与数据完整性。
- 性能问题:监控 Redis 延迟与内存占用,评估序列化体积与缓存大小。
章节来源
- [SysDeptServiceImplTest.java](file://crm-auth/src/test/java/com/crm/auth/service/impl/SysDeptServiceImplTest.java)
## 结论
部门管理模块以清晰的层次划分与完善的缓存机制为核心,提供了稳定高效的树形结构管理与 CRUD 能力。通过严格的层级校验与幂等初始化,保障了数据的正确性与可用性。在生产环境中,建议重点关注缓存一致性与性能指标,持续优化查询与写入路径。
[本节为总结性内容,不直接分析具体文件]
## 附录:API接口与使用案例
说明:以下为面向使用者的接口概览与调用示例,实际 Controller 层若存在,请结合项目中的控制器文件进一步查阅。
- 接口清单
- 获取部门树
- 方法:GET
- 路径:/api/dept/tree
- 请求参数:key(维度键,如租户ID)
- 返回:树形结构数组
- 新增部门
- 方法:POST
- 路径:/api/dept
- 请求体:{ name, code, parentId, sort, status }
- 返回:Result 包装
- 更新部门
- 方法:PUT
- 路径:/api/dept/{id}
- 请求体:{ name, code, parentId, sort, status }
- 返回:Result 包装
- 删除部门
- 方法:DELETE
- 路径:/api/dept/{id}
- 返回:Result 包装
- 批量移动/调整排序
- 方法:PATCH
- 路径:/api/dept/batch/update
- 请求体:[{ id, parentId, sort }]
- 返回:Result 包装
- 使用案例
- 初始化后首次获取树:调用 /api/dept/tree?key=tenant_001,命中缓存则直接返回,否则从 DB 构建并回填缓存。
- 新增子部门:先校验父部门存在,再插入并失效对应 key,下次读取自动重建。
- 调整排序:批量更新 sort,保持父子关系不变,失效缓存后重新构建。
[本节为概念性接口说明,不直接映射具体源码文件]