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.
 
 
 
 
 
 

50 KiB

基础框架模块(crm-base)

**本文引用的文件** - [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) - [BaseDTO.java](file://crm-base/src/main/java/com/crm/base/domain/dto/BaseDTO.java) - [BaseParam.java](file://crm-base/src/main/java/com/crm/base/domain/param/BaseParam.java) - [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java) - [PageResult.java](file://crm-base/src/main/java/com/crm/base/domain/result/PageResult.java) - [ResultCodeEnum.java](file://crm-base/src/main/java/com/crm/base/domain/result/ResultCodeEnum.java) - [StatusEnum.java](file://crm-base/src/main/java/com/crm/base/domain/enums/StatusEnum.java) - [HasValueEnum.java](file://crm-base/src/main/java/com/crm/base/domain/enums/HasValueEnum.java) - [CommonConstants.java](file://crm-base/src/main/java/com/crm/base/constant/CommonConstants.java) - [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java) - [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java) - [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java) - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) - [MetaObjectFillHandler.java](file://crm-base/src/main/java/com/crm/base/config/MetaObjectFillHandler.java) - [CustomIdGenerator.java](file://crm-base/src/main/java/com/crm/base/config/CustomIdGenerator.java) - [SnowflakeIdWorker.java](file://crm-base/src/main/java/com/crm/base/config/SnowflakeIdWorker.java) - [SnowflakeProperties.java](file://crm-base/src/main/java/com/crm/base/config/SnowflakeProperties.java) - [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java) - [JacksonConfig.java](file://crm-base/src/main/java/com/crm/base/config/JacksonConfig.java) - [Knife4jConfig.java](file://crm-base/src/main/java/com/crm/base/config/Knife4jConfig.java) - [CorsConfig.java](file://crm-base/src/main/java/com/crm/base/config/CorsConfig.java) - [InsertBatchOnDuplicateKeyUpdate.java](file://crm-base/src/main/java/com/crm/base/config/InsertBatchOnDuplicateKeyUpdate.java) - [TraceIdFilter.java](file://crm-base/src/main/java/com/crm/base/filter/TraceIdFilter.java) - [CrmBaseMapper.java](file://crm-base/src/main/java/com/crm/base/mapper/CrmBaseMapper.java) - [IBaseService.java](file://crm-base/src/main/java/com/crm/base/service/IBaseService.java) - [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java) - [AssertUtils.java](file://crm-base/src/main/java/com/crm/base/utils/AssertUtils.java) - [BeanCopyUtils.java](file://crm-base/src/main/java/com/crm/base/utils/BeanCopyUtils.java) - [EnumUtils.java](file://crm-base/src/main/java/com/crm/base/utils/EnumUtils.java) - [ExcelUtil.java](file://crm-base/src/main/java/com/crm/base/utils/ExcelUtil.java) - [PageConverter.java](file://crm-base/src/main/java/com/crm/base/utils/PageConverter.java) - [ServletUtils.java](file://crm-base/src/main/java/com/crm/base/utils/ServletUtils.java) - [TreeUtils.java](file://crm-base/src/main/java/com/crm/base/utils/TreeUtils.java) - [BusinessErrorException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/BusinessErrorException.java) - [MissingParameterException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/MissingParameterException.java) - [PermissionErrorException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/PermissionErrorException.java) - [ResourceNotExistException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/ResourceNotExistException.java) - [DataOwnership.java](file://crm-base/src/main/java/com/crm/base/security/DataOwnership.java) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java) - [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [LoginUser.java](file://crm-base/src/main/java/com/crm/base/security/LoginUser.java) - [SecurityUtils.java](file://crm-base/src/main/java/com/crm/base/security/SecurityUtils.java) - [DictGroup.java](file://crm-dict/src/main/java/com/crm/dict/domain/entity/DictGroup.java) - [DictItem.java](file://crm-dict/src/main/java/com/crm/dict/domain/entity/DictItem.java) - [DictGroupDefault.java](file://crm-dict/src/main/java/com/crm/dict/domain/entity/DictGroupDefault.java) - [DictRefCount.java](file://crm-dict/src/main/java/com/crm/dict/domain/entity/DictRefCount.java) - [DictGroupVO.java](file://crm-dict/src/main/java/com/crm/dict/domain/dto/DictGroupVO.java) - [DictItemVO.java](file://crm-dict/src/main/java/com/crm/dict/domain/dto/DictItemVO.java) - [DictGroupController.java](file://crm-dict/src/main/java/com/crm/dict/controller/DictGroupController.java) - [DictItemController.java](file://crm-dict/src/main/java/com/crm/dict/controller/DictItemController.java) - [IDictGroupService.java](file://crm-dict/src/main/java/com/crm/dict/service/IDictGroupService.java) - [IDictItemService.java](file://crm-dict/src/main/java/com/crm/dict/service/IDictItemService.java) - [DictGroupServiceImpl.java](file://crm-dict/src/main/java/com/crm/dict/service/impl/DictGroupServiceImpl.java) - [DictItemServiceImpl.java](file://crm-dict/src/main/java/com/crm/dict/service/impl/DictItemServiceImpl.java) - [DictDataInitializer.java](file://crm-dict/src/main/java/com/crm/dict/config/DictDataInitializer.java) - [DictPermissionInitializer.java](file://crm-dict/src/main/java/com/crm/dict/config/DictPermissionInitializer.java) - [DictConstants.java](file://crm-dict/src/main/java/com/crm/dict/constant/DictConstants.java)

更新摘要

变更内容

  • 更新了数据字典模块的VO设计架构,DictGroupVO和DictItemVO现在使用独立字段定义而非继承实体类
  • 增强了API设计的清晰度和安全性,通过明确的字段暴露控制敏感信息
  • 优化了服务层实现以适配新的VO结构,提升了数据转换效率
  • 完善了VO设计模式的最佳实践说明

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考量
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本模块为 CRM 后端的基础设施层,提供通用实体、分页与结果封装、全局异常处理、数据访问层封装、工具类以及 MyBatis Plus、Redis、雪花ID等关键配置。通过统一的设计模式与约定,降低业务模块重复开发成本,提升一致性与可维护性。

更新 新增 crm-dict 数据字典模块,作为独立的服务模块提供平台级键值字典管理能力,支持分组管理、字典项管理、引用计数和权限集成等功能。该模块采用了先进的VO设计模式,通过独立的视图对象定义提升了API的安全性和清晰度。

项目结构

crm-base 采用分层组织:

  • domain:通用实体、DTO、参数、枚举、异常、结果封装
  • config:MyBatis Plus、Redis、Jackson、Knife4j、跨域、SQL注入器、填充处理器、ID生成器等
  • service/mapper:通用服务接口与实现、基础 Mapper
  • advice/filter:全局异常处理、请求链路追踪过滤器
  • security:数据权限控制、可见性上下文、登录用户模型与安全工具
  • utils:通用工具集(断言、拷贝、枚举、Excel、分页转换、Servlet、树形结构)

更新 crm-dict 模块结构:

  • controller:字典分组和字典项的管理接口
  • service:字典查询、引用计数、分组和字典项的业务逻辑
  • domain:字典实体、DTO、参数定义,采用独立VO设计模式
  • config:内置数据初始化、权限种子化配置
  • constant:字典模块常量定义
graph TB
subgraph "基础框架 (crm-base)"
A["BaseEntity / OwnedEntity"]
B["BaseDTO / BaseParam"]
C["Result / PageResult / ResultCodeEnum"]
D["StatusEnum / HasValueEnum"]
E["MybatisPlusConfig / CrmSqlInjector"]
F["RedisConfig / JacksonConfig"]
G["GlobalExceptionHandlerAdvice"]
H["DataScope / SecurityUtils"]
end
subgraph "数据字典 (crm-dict)"
I["DictGroup / DictItem"]
J["DictGroupVO / DictItemVO"]
K["DictGroupController / DictItemController"]
L["IDictGroupService / IDictItemService"]
M["DictDataInitializer / DictPermissionInitializer"]
N["DictConstants"]
end
A --> L
B --> L
C --> K
E --> L
F --> M
G --> K
H --> K
I --> J
J --> K
L --> E
M --> I
N --> L

图表来源

  • BaseEntity.java
  • DictGroup.java
  • DictItem.java
  • DictGroupVO.java
  • DictItemVO.java
  • DictGroupController.java
  • IDictGroupService.java
  • DictDataInitializer.java

章节来源

  • BaseEntity.java
  • DictGroup.java
  • MybatisPlusConfig.java
  • RedisConfig.java

核心组件

  • 通用实体与继承体系
    • BaseEntity:定义统一的审计字段(如创建时间、更新时间、逻辑删除标记等),配合元数据填充处理器自动落库。
    • OwnedEntity:在 BaseEntity 基础上扩展数据归属字段(如所属部门/租户),支撑数据权限过滤。
  • 通用 DTO/Param
    • BaseDTO:作为对象转换的基类,便于与实体解耦。
    • BaseParam:作为查询/操作参数的基类,统一分页、排序等公共字段。
  • 统一结果与分页
    • Result:标准响应体,包含状态码、消息与数据。
    • PageResult:分页结果封装,适配 MyBatis Plus 的分页对象。
    • ResultCodeEnum:统一错误码枚举。
  • 枚举与常量
    • StatusEnum、HasValueEnum:常用状态与布尔值语义化枚举。
    • CommonConstants:系统级常量。
  • 数据访问封装
    • CrmBaseMapper:基础 Mapper,扩展通用方法。
    • IBaseService / BaseServiceImpl:CRUD 抽象,结合分页、批量插入、更新策略等。
  • 全局异常处理
    • GlobalExceptionHandlerAdvice:集中捕获业务异常、参数异常、权限异常等,返回统一 Result。
  • 安全与数据权限
    • DataScope 注解 + DataScopeHelper:声明式数据范围控制。
    • DataVisibilityContext:线程可见性上下文,存储当前用户的数据范围。
    • SecurityUtils / LoginUser:获取当前登录用户信息。
  • 基础设施配置
    • MyBatis Plus 配置:分页插件、SQL 注入器、填充处理器、自定义 ID 生成器。
    • Redis 配置:序列化、连接池、过期策略等。
    • Jackson 配置:日期、空值、时区等序列化策略。
    • Knife4j 配置:API 文档增强。
    • CorsConfig:跨域支持。
    • InsertBatchOnDuplicateKeyUpdate:批量插入去重策略。
    • TraceIdFilter:请求链路追踪。
  • 工具类
    • AssertUtils、BeanCopyUtils、EnumUtils、ExcelUtil、PageConverter、ServletUtils、TreeUtils。

更新 数据字典核心组件:

  • 字典实体:DictGroup(分组)、DictItem(字典项)、DictGroupDefault(默认项)、DictRefCount(引用计数)
  • VO设计模式:DictGroupVO和DictItemVO采用独立字段定义,不继承实体类,提供更清晰的API契约
  • 控制器:DictGroupController、DictItemController 提供 RESTful API
  • 服务层:IDictGroupService、IDictItemService 定义业务接口
  • 初始化器:DictDataInitializer(内置数据)、DictPermissionInitializer(权限种子)
  • 常量定义:DictConstants 包含状态码、权限码、缓存配置等

章节来源

  • BaseEntity.java
  • OwnedEntity.java
  • BaseDTO.java
  • BaseParam.java
  • Result.java
  • PageResult.java
  • ResultCodeEnum.java
  • StatusEnum.java
  • HasValueEnum.java
  • CommonConstants.java
  • CrmBaseMapper.java
  • IBaseService.java
  • BaseServiceImpl.java
  • GlobalExceptionHandlerAdvice.java
  • DataScope.java
  • DataScopeHelper.java
  • DataVisibilityContext.java
  • SecurityUtils.java
  • LoginUser.java
  • MybatisPlusConfig.java
  • RedisConfig.java
  • JacksonConfig.java
  • Knife4jConfig.java
  • CorsConfig.java
  • InsertBatchOnDuplicateKeyUpdate.java
  • TraceIdFilter.java
  • AssertUtils.java
  • BeanCopyUtils.java
  • EnumUtils.java
  • ExcelUtil.java
  • PageConverter.java
  • ServletUtils.java
  • TreeUtils.java
  • DictGroup.java
  • DictItem.java
  • DictGroupDefault.java
  • DictRefCount.java
  • DictGroupVO.java
  • DictItemVO.java
  • DictGroupController.java
  • DictItemController.java
  • IDictGroupService.java
  • IDictItemService.java
  • DictGroupServiceImpl.java
  • DictItemServiceImpl.java
  • DictDataInitializer.java
  • DictPermissionInitializer.java
  • DictConstants.java

架构总览

基础框架围绕"实体-服务-Mapper"三层展开,辅以配置中心与横切能力:

  • 实体层:BaseEntity/OwnedEntity 提供统一字段与审计;OwnedEntity 承载数据归属。
  • 服务层:IBaseService/BaseServiceImpl 提供 CRUD、分页、批量操作与事务边界。
  • 数据层:CrmBaseMapper 扩展通用 SQL;MyBatis Plus 插件负责分页、填充、ID 生成。
  • 横切:全局异常、数据权限、请求追踪、序列化、缓存、API 文档、跨域。

更新 新增 crm-dict 模块架构:

  • 独立服务模块:基于 crm-base 构建,不依赖 crm-auth 具体实现
  • 两级字典结构:分组 → 字典项,支持内置和用户字典分离
  • VO设计模式:采用独立的视图对象(DictGroupVO、DictItemVO)替代实体继承,提升API安全性和清晰度
  • 引用计数机制:跟踪字典项使用情况,防止误删
  • 权限集成:通过权限码契约与 crm-auth 解耦集成
  • 本地缓存:使用 Caffeine 提供高性能字典查询缓存
classDiagram
class BaseEntity {
+id
+createTime
+updateTime
+deleted
}
class OwnedEntity {
+ownerId
+deptId
}
class DictGroup {
+code
+name
+status
+builtin
+deleteKey
}
class DictItem {
+groupId
+code
+name
+value
+status
+builtin
+deleteKey
}
class DictGroupVO {
+id
+name
+code
+sortNo
+status
+description
+builtin
+createTime
+itemCount
}
class DictItemVO {
+id
+groupId
+name
+code
+value
+sortNo
+status
+description
+builtin
+createTime
+groupName
+isDefault
+referenced
+effectiveSelectable
}
class DictGroupDefault {
+groupId
+itemId
}
class DictRefCount {
+groupCode
+itemCode
+refCount
}
class IBaseService~T~ {
+save(entity)
+updateById(entity)
+removeById(id)
+getById(id)
+list(param)
+page(param)
+batchSave(list)
}
class IDictGroupService {
+pageGroups(param)
+saveGroup(group)
+deleteGroup(id)
+updateGroupStatus(id, status)
+listEnabled()
}
class IDictItemService {
+pageItems(param)
+saveItem(item)
+deleteItem(id)
+forceDeleteItem(id)
+updateItemStatus(id, status)
+setDefault(groupId, itemId)
}
class DictDataInitializer
class DictPermissionInitializer
OwnedEntity --|> BaseEntity
DictGroup --> DictGroupDefault : "一对多"
DictItem --> DictRefCount : "引用计数"
IDictGroupService --> IBaseService : "继承"
IDictItemService --> IBaseService : "继承"
DictDataInitializer --> DictGroup : "初始化"
DictDataInitializer --> DictItem : "初始化"
DictPermissionInitializer --> DictGroup : "权限绑定"

图表来源

  • BaseEntity.java
  • OwnedEntity.java
  • DictGroup.java
  • DictItem.java
  • DictGroupVO.java
  • DictItemVO.java
  • DictGroupDefault.java
  • DictRefCount.java
  • IBaseService.java
  • IDictGroupService.java
  • IDictItemService.java
  • DictDataInitializer.java
  • DictPermissionInitializer.java

详细组件分析

通用实体与数据归属

  • BaseEntity 提供统一审计字段,配合 MetaObjectFillHandler 自动填充创建/更新时间、操作人等。
  • OwnedEntity 扩展数据归属字段,用于数据权限过滤(如按部门/租户隔离)。
  • 建议所有业务实体继承 OwnedEntity,确保数据权限生效。
classDiagram
class BaseEntity {
+id
+createTime
+updateTime
+deleted
}
class OwnedEntity {
+ownerId
+deptId
}
OwnedEntity --|> BaseEntity

图表来源

  • BaseEntity.java
  • OwnedEntity.java

章节来源

  • BaseEntity.java
  • OwnedEntity.java
  • MetaObjectFillHandler.java

分页与结果封装

  • PageResult 封装分页数据,适配 MyBatis Plus 的分页对象,提供 total/pages/current/size/records。
  • Result 统一响应格式,ResultCodeEnum 统一定义状态码。
  • PageConverter 提供将业务分页对象转换为 PageResult 的工具方法。
flowchart TD
Start(["进入分页查询"]) --> BuildParam["构建查询参数(BaseParam)"]
BuildParam --> QueryDB["调用 Service.page()"]
QueryDB --> Convert["PageConverter 转换"]
Convert --> Wrap["包装为 PageResult"]
Wrap --> Return["返回 Result.success(PageResult)"]

图表来源

  • PageResult.java
  • Result.java
  • ResultCodeEnum.java
  • PageConverter.java
  • IBaseService.java
  • BaseServiceImpl.java

章节来源

  • PageResult.java
  • Result.java
  • ResultCodeEnum.java
  • PageConverter.java

数据访问层封装与 CRUD

  • CrmBaseMapper:基础 Mapper,扩展通用方法,减少样板代码。
  • IBaseService/BaseServiceImpl:提供 save/update/remove/get/list/page/batchSave 等通用方法,内部集成分页、填充、ID 生成与事务管理。
  • 批量插入策略:InsertBatchOnDuplicateKeyUpdate 提供幂等写入能力。
sequenceDiagram
participant C as "Controller"
participant S as "BaseServiceImpl"
participant M as "CrmBaseMapper"
participant MP as "MyBatis Plus"
C->>S : "page(BaseParam)"
S->>MP : "构造分页查询(含数据权限)"
MP->>M : "执行 SQL"
M-->>MP : "返回记录集"
MP-->>S : "分页对象"
S-->>C : "PageResult"

图表来源

  • CrmBaseMapper.java
  • IBaseService.java
  • BaseServiceImpl.java
  • MybatisPlusConfig.java

章节来源

  • CrmBaseMapper.java
  • IBaseService.java
  • BaseServiceImpl.java
  • InsertBatchOnDuplicateKeyUpdate.java

全局异常处理机制

  • GlobalExceptionHandlerAdvice 集中捕获业务异常、参数缺失、权限错误、资源不存在等,统一返回 Result。
  • 自定义异常类型:BusinessErrorException、MissingParameterException、PermissionErrorException、ResourceNotExistException。
  • 建议业务层抛出明确异常,由该拦截器统一收敛。
flowchart TD
Entry(["请求进入"]) --> TryBlock["执行业务逻辑"]
TryBlock --> Success{"是否成功?"}
Success --> |是| Ok["返回 Result.success(data)"]
Success --> |否| Catch["捕获特定异常"]
Catch --> Map["映射为 Result.error(code,message)"]
Map --> End(["返回统一响应"])

图表来源

  • GlobalExceptionHandlerAdvice.java
  • BusinessErrorException.java
  • MissingParameterException.java
  • PermissionErrorException.java
  • ResourceNotExistException.java
  • Result.java

章节来源

  • GlobalExceptionHandlerAdvice.java
  • BusinessErrorException.java
  • MissingParameterException.java
  • PermissionErrorException.java
  • ResourceNotExistException.java

数据权限控制

  • DataScope 注解:标注在方法或类上,声明数据范围级别。
  • DataScopeHelper:解析注解并组装 WHERE 条件(如 deptId/ownerId)。
  • DataVisibilityContext:线程内保存当前用户的数据可见范围。
  • SecurityUtils/LoginUser:从上下文获取当前登录用户信息。
sequenceDiagram
participant U as "调用方"
participant S as "Service方法"
participant DS as "DataScopeHelper"
participant CTX as "DataVisibilityContext"
U->>S : "带@DataScope的方法调用"
S->>DS : "解析注解与用户范围"
DS->>CTX : "设置可见范围"
DS-->>S : "返回过滤条件片段"
S-->>U : "返回受限数据集合"

图表来源

  • DataScope.java
  • DataScopeHelper.java
  • DataVisibilityContext.java
  • SecurityUtils.java
  • LoginUser.java

章节来源

  • DataScope.java
  • DataScopeHelper.java
  • DataVisibilityContext.java
  • SecurityUtils.java
  • LoginUser.java

MyBatis Plus 配置与扩展

  • MybatisPlusConfig:注册分页插件、SQL 注入器、填充处理器、自定义 ID 生成器。
  • CrmSqlInjector:扩展通用 SQL 片段与方法。
  • MetaObjectFillHandler:自动填充审计字段(创建时间、更新时间、操作人等)。
  • CustomIdGenerator:基于 SnowflakeIdWorker 生成分布式唯一 ID。
  • SnowflakeProperties:雪花算法相关配置(工作节点、数据中心等)。
flowchart TD
Init["应用启动"] --> Register["注册 MyBatis Plus 插件"]
Register --> Fill["注册 MetaObjectFillHandler"]
Register --> Inject["注册 CrmSqlInjector"]
Register --> IdGen["注册 CustomIdGenerator"]
IdGen --> Snow["SnowflakeIdWorker 生成ID"]
Fill --> Audit["自动填充审计字段"]
Inject --> SQL["扩展通用 SQL"]

图表来源

  • MybatisPlusConfig.java
  • CrmSqlInjector.java
  • MetaObjectFillHandler.java
  • CustomIdGenerator.java
  • SnowflakeIdWorker.java
  • SnowflakeProperties.java

章节来源

  • MybatisPlusConfig.java
  • CrmSqlInjector.java
  • MetaObjectFillHandler.java
  • CustomIdGenerator.java
  • SnowflakeIdWorker.java
  • SnowflakeProperties.java

Redis 集成与缓存配置

  • RedisConfig:配置序列化、连接池、默认过期策略等,供业务模块按需使用。
  • 建议对热点数据(字典、菜单树、权限等)进行缓存,注意一致性策略与失效时机。
flowchart TD
App["应用启动"] --> RConf["初始化 RedisConfig"]
RConf --> Serializer["配置序列化器"]
RConf --> Pool["配置连接池"]
RConf --> TTL["设置默认过期策略"]
App --> Use["业务模块使用 RedisTemplate"]

图表来源

  • RedisConfig.java

章节来源

  • RedisConfig.java

Jackson 与 API 文档、跨域

  • JacksonConfig:统一日期格式、时区、空值序列化策略。
  • Knife4jConfig:增强 Swagger 文档体验。
  • CorsConfig:允许跨域访问,便于前后端分离开发。

章节来源

  • JacksonConfig.java
  • Knife4jConfig.java
  • CorsConfig.java

工具类与辅助能力

  • AssertUtils:参数校验与断言。
  • BeanCopyUtils:对象属性拷贝。
  • EnumUtils:枚举工具方法。
  • ExcelUtil:导入导出 Excel。
  • PageConverter:分页对象转换。
  • ServletUtils:HTTP 请求辅助。
  • TreeUtils:树形结构构建。

章节来源

  • AssertUtils.java
  • BeanCopyUtils.java
  • EnumUtils.java
  • ExcelUtil.java
  • PageConverter.java
  • ServletUtils.java
  • TreeUtils.java

数据字典模块详解

VO设计模式重构

更新 数据字典模块采用了先进的VO设计模式,DictGroupVO和DictItemVO现在使用独立的字段定义而非继承实体类,显著提升了API设计的清晰度和安全性。

  • DictGroupVO:专门用于分页列表展示的视图对象,只暴露前端需要的业务字段(id、name、code、sortNo、status、description、builtin、createTime、itemCount),排除了敏感的审计字段(creatorId/updaterId/updateTime/deleted)和软删内部字段(deleteKey)。
  • DictItemVO:字典项视图对象,包含丰富的展示字段(groupName、isDefault、referenced、effectiveSelectable),其中referenced字段实时读取引用计数,绝不进缓存,确保数据准确性。
classDiagram
class BaseEntity {
+id
+createTime
+updateTime
+deleted
}
class DictGroup {
+code
+name
+status
+builtin
+deleteKey
}
class DictItem {
+groupId
+code
+name
+value
+status
+builtin
+deleteKey
}
class DictGroupVO {
+id
+name
+code
+sortNo
+status
+description
+builtin
+createTime
+itemCount
}
class DictItemVO {
+id
+groupId
+name
+code
+value
+sortNo
+status
+description
+builtin
+createTime
+groupName
+isDefault
+referenced
+effectiveSelectable
}
DictGroup --> DictGroupVO : "toDTO()"
DictItem --> DictItemVO : "toDTO()"

图表来源

  • BaseEntity.java
  • DictGroup.java
  • DictItem.java
  • DictGroupVO.java
  • DictItemVO.java

核心实体设计

  • DictGroup(字典分组):字典的第一级容器,具有全局唯一编码,创建后不可修改。支持内置标记区分平台内置和用户自定义字典。
  • DictItem(字典项):字典的第二级键值条目,身份由{分组ID, 编码}确定,创建后不可修改。支持字典值同组唯一约束。
  • DictGroupDefault(分组默认项):通过主键约束保证每组最多一个默认项,独立表存储避免污染字典项实体。
  • DictRefCount(引用计数):跟踪字典项被业务数据引用的次数,防止误删已使用的字典项。
classDiagram
class DictGroup {
+Long id
+String code
+String name
+Integer sortNo
+Integer status
+Boolean builtin
+Long deleteKey
}
class DictItem {
+Long id
+Long groupId
+String code
+String name
+String value
+Integer sortNo
+Integer status
+Boolean builtin
+Long deleteKey
}
class DictGroupDefault {
+Long groupId
+Long itemId
}
class DictRefCount {
+String groupCode
+String itemCode
+Integer refCount
}
DictGroup "1" --> "0..*" DictItem : "拥有"
DictGroup "1" --> "0..1" DictGroupDefault : "默认项"
DictItem "1" --> "0..1" DictRefCount : "引用计数"

图表来源

  • DictGroup.java
  • DictItem.java
  • DictGroupDefault.java
  • DictRefCount.java

控制器与服务层

  • DictGroupController:提供分组管理的 RESTful API,包括分页查询、新建编辑、删除、启停等操作。
  • DictItemController:提供字典项管理的 RESTful API,支持分页查询、CRUD、默认项设置、强制删除等功能。
  • IDictGroupService/IDictItemService:定义业务接口,继承 IBaseService 获得通用 CRUD 能力。
  • DictGroupServiceImpl:实现分组业务逻辑,包含数据验证、权限检查、事务管理等。
sequenceDiagram
participant Client as "客户端"
participant Controller as "DictGroupController"
participant Service as "IDictGroupService"
participant DB as "数据库"
Client->>Controller : POST /api/dict/group/saveOrUpdate
Controller->>Service : saveGroup(DictGroup)
Service->>Service : 数据验证与权限检查
Service->>DB : INSERT/UPDATE dict_group
DB-->>Service : 操作结果
Service-->>Controller : 业务结果
Controller-->>Client : Result.success()

图表来源

  • DictGroupController.java
  • IDictGroupService.java
  • DictGroupServiceImpl.java

初始化与权限集成

  • DictDataInitializer:应用启动时执行内置字典的幂等初始化,支持 Excel 替换口,保护用户字典不被覆盖。
  • DictPermissionInitializer:权限种子化,将 10 个 dict:* 权限点注入到权限资源树,并与管理员角色绑定。
  • DictConstants:集中定义状态码、权限码、缓存配置、错误码等常量。
flowchart TD
Startup["应用启动"] --> DataInit["DictDataInitializer.run()"]
Startup --> PermInit["DictPermissionInitializer.run()"]
DataInit --> Validate["校验种子数据"]
Validate --> UpsertGroup["upsertGroup()"]
UpsertGroup --> UpsertItem["upsertItem()"]
UpsertItem --> SetDefault["setDefaultIfAbsent()"]
PermInit --> CreateMenu["创建菜单节点"]
CreateMenu --> CreateButtons["创建权限按钮"]
CreateButtons --> BindRole["绑定管理员角色"]

图表来源

  • DictDataInitializer.java
  • DictPermissionInitializer.java
  • DictConstants.java

章节来源

  • DictGroup.java
  • DictItem.java
  • DictGroupDefault.java
  • DictRefCount.java
  • DictGroupVO.java
  • DictItemVO.java
  • DictGroupController.java
  • DictItemController.java
  • IDictGroupService.java
  • IDictItemService.java
  • DictGroupServiceImpl.java
  • DictItemServiceImpl.java
  • DictDataInitializer.java
  • DictPermissionInitializer.java
  • DictConstants.java

依赖关系分析

  • 实体与服务:BaseEntity/OwnedEntity 被 BaseServiceImpl 广泛使用;IBaseService 定义契约。
  • 数据访问:CrmBaseMapper 被 BaseServiceImpl 依赖;MyBatis Plus 插件贯穿整个数据层。
  • 横切:GlobalExceptionHandlerAdvice 作用于所有 Controller;DataScopeHelper 与 DataVisibilityContext 影响查询条件。
  • 外部依赖:Redis 用于缓存;Jackson 用于序列化;Knife4j 用于文档;Cors 用于跨域。

更新 新增 crm-dict 模块依赖关系:

  • crm-dict 仅依赖 crm-base,不直接依赖 crm-auth,通过权限码契约解耦
  • 使用 Caffeine 本地缓存提升字典查询性能
  • 通过 CommandLineRunner 实现启动时初始化
  • 与 crm-auth 通过权限资源树间接集成
  • VO设计模式:通过独立的视图对象减少了实体与API的直接耦合
graph LR
Entity["BaseEntity/OwnedEntity"] --> Service["IBaseService/BaseServiceImpl"]
Service --> Mapper["CrmBaseMapper"]
Service --> MP["MyBatisPlusConfig"]
MP --> Fill["MetaObjectFillHandler"]
MP --> ID["CustomIdGenerator/SnowflakeIdWorker"]
Service --> Cache["RedisConfig"]
Controller["业务Controller"] --> Service
Controller --> Exception["GlobalExceptionHandlerAdvice"]
Service --> Scope["DataScopeHelper/DataVisibilityContext"]
DictModule["crm-dict 模块"] --> BaseModule["crm-base 模块"]
DictModule --> Caffeine["Caffeine 缓存"]
DictModule --> AuthContract["权限码契约"]
AuthContract --> AuthModule["crm-auth 模块"]
DictModule --> VOPattern["VO设计模式"]
VOPattern --> APIClear["清晰的API契约"]

图表来源

  • BaseEntity.java
  • OwnedEntity.java
  • IBaseService.java
  • BaseServiceImpl.java
  • CrmBaseMapper.java
  • MybatisPlusConfig.java
  • MetaObjectFillHandler.java
  • CustomIdGenerator.java
  • SnowflakeIdWorker.java
  • RedisConfig.java
  • GlobalExceptionHandlerAdvice.java
  • DataScopeHelper.java
  • DataVisibilityContext.java
  • pom.xml

章节来源

  • BaseServiceImpl.java
  • MybatisPlusConfig.java
  • RedisConfig.java
  • GlobalExceptionHandlerAdvice.java
  • pom.xml

性能考量

  • 分页查询:优先使用 MyBatis Plus 分页插件,避免全表扫描;合理设计索引。
  • 批量操作:使用 batchSave 与 InsertBatchOnDuplicateKeyUpdate 提升写入吞吐。
  • 缓存策略:对热点数据启用 Redis 缓存,设置合理 TTL 与失效策略。
  • 序列化:Jackson 配置统一时区与空值策略,减少序列化开销。
  • 审计填充:MetaObjectFillHandler 仅在必要时填充,避免多余数据库写操作。

更新 数据字典性能优化:

  • 使用 Caffeine 本地缓存提供 10s TTL 的字典查询缓存
  • 空结果缓存 2s 防穿透,避免缓存击穿
  • 引用计数表不缓存,保证数据一致性
  • 聚合查询优化:分组分页时一次性查询字典项数量
  • 默认排序优化:sort_no IS NULL, sort_no ASC, create_time ASC
  • VO设计优化:通过独立的VO对象减少数据传输量,提升网络传输效率

[本节为通用指导,不直接分析具体文件]

故障排查指南

  • 统一异常:检查 GlobalExceptionHandlerAdvice 是否捕获到预期异常类型,确认 ResultCodeEnum 的状态码与消息。
  • 数据权限:确认 DataScope 注解是否正确标注,DataVisibilityContext 中可见范围是否设置正确。
  • 填充失败:检查 MetaObjectFillHandler 是否注册,实体字段名是否与填充规则匹配。
  • ID 冲突:核对 SnowflakeIdWorker 配置(工作节点/数据中心)是否唯一,避免 ID 碰撞。
  • 缓存问题:检查 Redis 连接与序列化配置,确认 key 命名规范与过期策略。
  • 跨域与文档:验证 CorsConfig 与 Knife4jConfig 配置是否符合前端需求。

更新 数据字典故障排查:

  • 初始化失败:检查 DictDataInitializer 的种子数据合法性,确认 fail-fast 机制
  • 权限问题:验证 DictPermissionInitializer 是否正确创建菜单和权限点
  • 缓存不一致:检查 Caffeine 缓存配置,确认 TTL 设置合理
  • 引用计数异常:监控 DictRefCount 表的计数准确性,必要时使用强制删除功能
  • 内置字典保护:确认 builtin=true 的字典项无法被删除或修改关键字段
  • VO设计问题:检查DictGroupVO和DictItemVO的字段映射是否正确,确保toDTO方法正常工作

章节来源

  • GlobalExceptionHandlerAdvice.java
  • DataScopeHelper.java
  • MetaObjectFillHandler.java
  • SnowflakeIdWorker.java
  • RedisConfig.java
  • CorsConfig.java
  • Knife4jConfig.java
  • DictDataInitializer.java
  • DictPermissionInitializer.java

结论

crm-base 提供了完善的基础设施能力,涵盖实体设计、CRUD 封装、分页与结果统一、全局异常、数据权限、MyBatis Plus 扩展、Redis 缓存、雪花 ID 生成等。遵循本模块约定,可显著提升业务模块的开发效率与一致性。

更新 新增 crm-dict 数据字典模块作为独立的基础设施服务,提供平台级的键值字典管理能力。该模块通过先进的VO设计模式重构,实现了更清晰的API契约和更高的安全性,同时通过解耦设计与权限码契约,实现了与认证模块的松耦合集成。VO设计模式的采用使得数据展示更加灵活可控,有效避免了敏感信息的泄露风险。

[本节为总结性内容,不直接分析具体文件]

附录

最佳实践

  • 实体设计
    • 所有业务实体继承 OwnedEntity,确保数据权限生效。
    • 合理使用审计字段,避免频繁手动更新 createTime/updateTime。
  • 服务层
    • 优先使用 IBaseService 提供的通用方法,减少样板代码。
    • 复杂查询通过 CrmBaseMapper 扩展 SQL,保持可读性。
  • 异常处理
    • 业务层抛出明确的自定义异常,交由 GlobalExceptionHandlerAdvice 统一处理。
  • 数据权限
    • 在需要数据隔离的方法上使用 @DataScope,并通过 DataVisibilityContext 设置可见范围。
  • 缓存
    • 对热点数据使用 Redis 缓存,设置合理的 TTL 与失效策略,保证一致性。
  • 工具类
    • 使用 AssertUtils 做前置校验;使用 BeanCopyUtils 进行对象转换;使用 PageConverter 转换分页对象。

更新 数据字典最佳实践:

  • 字典设计:优先使用内置字典,用户字典用于个性化需求
  • 编码规范:字典编码使用有意义的英文标识,避免使用数字 ID
  • 引用管理:业务代码中正确使用引用计数增减,避免内存泄漏
  • 缓存策略:利用 Caffeine 本地缓存提升查询性能,注意缓存失效时机
  • 权限控制:通过权限码进行细粒度控制,避免硬编码权限判断
  • VO设计模式:采用独立的视图对象定义API契约,避免直接暴露实体字段,提升安全性和灵活性

[本节为通用指导,不直接分析具体文件]

扩展开发指南

  • 新增实体
    • 继承 OwnedEntity,定义必要字段;如需自定义 ID 生成策略,可在 CustomIdGenerator 中扩展。
  • 新增服务方法
    • 在 IBaseService 中定义接口,在 BaseServiceImpl 中实现;复杂 SQL 通过 CrmBaseMapper 扩展。
  • 新增数据权限级别
    • 在 DataScopeLevel 中扩展级别,并在 DataScopeHelper 中实现对应过滤逻辑。
  • 新增缓存键与策略
    • 在业务模块中定义缓存 Key 前缀与过期时间,使用 RedisTemplate 进行操作。
  • 新增全局异常类型
    • 定义新的异常类,并在 GlobalExceptionHandlerAdvice 中添加对应的处理分支。

更新 数据字典扩展指南:

  • 新增字典分组:通过 DictGroupController 的 saveOrUpdate 接口创建新分组
  • 新增字典项:使用 DictItemController 的 saveOrUpdate 接口添加字典项
  • 扩展内置数据:修改 DictDataInitializer 中的 SEED_GROUPS 列表
  • 新增权限点:在 DictPermissionInitializer 中添加新的权限点种子
  • 自定义缓存策略:扩展 DictConstants 中的缓存配置参数
  • VO扩展:如需新增展示字段,应在DictGroupVO和DictItemVO中定义独立字段,而非修改实体类

[本节为通用指导,不直接分析具体文件]