# 部门管理 **本文引用的文件** - [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) ## 目录 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,保持父子关系不变,失效缓存后重新构建。 [本节为概念性接口说明,不直接映射具体源码文件]