26 KiB
领域模型
**本文引用的文件** - [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) - [BeanCopyUtils.java](file://crm-base/src/main/java/com/crm/base/utils/BeanCopyUtils.java) - [PageConverter.java](file://crm-base/src/main/java/com/crm/base/utils/PageConverter.java) - [AssertUtils.java](file://crm-base/src/main/java/com/crm/base/utils/AssertUtils.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) - [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.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) - [LoginParam.java](file://crm-auth/src/main/java/com/crm/auth/domain/param/LoginParam.java) - [UserInfoDTO.java](file://crm-auth/src/main/java/com/crm/auth/domain/dto/UserInfoDTO.java) - [MenuType.java](file://crm-auth/src/main/java/com/crm/auth/domain/enums/MenuType.java) - [ResourceNode.java](file://crm-auth/src/main/java/com/crm/auth/domain/dto/ResourceNode.java) - [SysMenu.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysMenu.java)更新摘要
所做更改
- 更新了菜单类型枚举的统一化说明,移除已废弃的MenuTypeEnum引用
- 新增MenuType枚举的详细使用说明和最佳实践
- 更新了ResourceNode DTO与MenuType的集成示例
- 完善了领域模型中枚举类型的标准化指导
目录
简介
本文件面向领域模型与数据契约,系统性说明 BaseDTO、BaseParam 的基类设计与继承关系,统一响应 Result 与分页结果 PageResult 的结构与用法,阐述 DTO 与 Param 的设计原则、字段验证规则与转换策略,并给出领域模型的扩展指导与自定义数据对象的创建规范。目标是帮助开发者在 CRM 后端项目中以一致、可维护的方式定义数据传输对象、参数对象以及统一的接口响应格式。
更新 本项目已统一菜单类型枚举,移除了废弃的MenuTypeEnum,仅保留MenuType(CATALOG/MENU/BUTTON)作为权威定义,确保领域模型词汇的一致性。
项目结构
本项目采用多模块组织,领域模型相关的基础类型集中在 crm-base 模块中,业务模块(如 crm-auth)通过引入基础模块复用这些通用能力。关键位置如下:
- 基础 DTO 与 Param:crm-base/domain/{dto,param}
- 统一响应封装:crm-base/domain/result
- 工具与转换器:crm-base/utils
- 异常与全局处理:crm-base/advice 与 crm-base/domain/exception
- 实体基类:crm-base/domain/entity
- 业务枚举:crm-auth/domain/enums(包含统一的MenuType)
graph TB
subgraph "基础模块 crm-base"
A["domain/dto/BaseDTO"]
B["domain/param/BaseParam"]
C["domain/result/Result"]
D["domain/result/PageResult"]
E["utils/BeanCopyUtils"]
F["utils/PageConverter"]
G["advice/GlobalExceptionHandlerAdvice"]
H["domain/entity/BaseEntity"]
I["domain/entity/OwnedEntity"]
end
subgraph "业务模块 crm-auth"
J["domain/param/LoginParam"]
K["domain/dto/UserInfoDTO"]
L["domain/enums/MenuType"]
M["domain/dto/ResourceNode"]
N["domain/entity/SysMenu"]
end
A --> C
B --> C
D --> C
E --> A
E --> B
F --> D
G --> C
H --> I
J --> B
K --> A
L --> M
M --> N
图表来源
- BaseDTO.java
- BaseParam.java
- Result.java
- PageResult.java
- BeanCopyUtils.java
- PageConverter.java
- GlobalExceptionHandlerAdvice.java
- BaseEntity.java
- OwnedEntity.java
- LoginParam.java
- UserInfoDTO.java
- MenuType.java
- ResourceNode.java
- SysMenu.java
章节来源
- BaseDTO.java
- BaseParam.java
- Result.java
- PageResult.java
- BeanCopyUtils.java
- PageConverter.java
- GlobalExceptionHandlerAdvice.java
- BaseEntity.java
- OwnedEntity.java
- LoginParam.java
- UserInfoDTO.java
- MenuType.java
- ResourceNode.java
- SysMenu.java
核心组件
- BaseDTO:所有数据传输对象的基类,提供统一的序列化、审计或扩展字段约定,便于跨层传递数据。
- BaseParam:所有请求参数的基类,集中承载校验注解、分页与排序等通用能力,简化 Controller 入参定义。
- Result:统一响应封装,包含状态码、消息与数据体,确保前后端交互一致性。
- PageResult:分页结果封装,聚合页码、总数、列表数据等分页元信息。
- BeanCopyUtils:对象拷贝工具,用于 DTO/Param/Entity 之间的属性映射与转换。
- PageConverter:分页转换工具,将框架分页对象转换为 PageResult。
- AssertUtils:断言工具,用于快速进行参数合法性校验。
- GlobalExceptionHandlerAdvice:全局异常处理器,将业务异常转换为统一 Result。
- MenuType:统一的菜单类型枚举,定义了CATALOG(目录)、MENU(菜单)、BUTTON(按钮)三种类型,替代了之前废弃的MenuTypeEnum。
章节来源
- BaseDTO.java
- BaseParam.java
- Result.java
- PageResult.java
- BeanCopyUtils.java
- PageConverter.java
- AssertUtils.java
- GlobalExceptionHandlerAdvice.java
- MenuType.java
架构总览
下图展示了领域模型在请求链路中的角色与交互:Controller 接收 BaseParam 派生参数,经服务层处理返回 Result 或 PageResult;DTO 作为跨层数据载体,通过 BeanCopyUtils 与 Entity 相互转换。MenuType 作为统一的领域概念,贯穿整个权限资源树的管理流程。
sequenceDiagram
participant Client as "客户端"
participant Controller as "控制器"
participant Service as "服务层"
participant Utils as "工具类"
participant Response as "统一响应"
Client->>Controller : "HTTP 请求(BaseParam)"
Controller->>Controller : "参数校验(注解/断言)"
Controller->>Service : "调用业务方法"
Service->>Utils : "对象转换(BeanCopyUtils)"
Service->>Service : "MenuType 验证(isLegalChild)"
Service-->>Controller : "业务结果(DTO/Entity)"
Controller->>Response : "封装为Result/PageResult"
Response-->>Client : "JSON 响应"
图表来源
- GlobalExceptionHandlerAdvice.java
- BeanCopyUtils.java
- Result.java
- PageResult.java
- MenuType.java
详细组件分析
BaseDTO 与 BaseParam 基类设计
- BaseDTO
- 职责:作为数据传输对象的基类,统一序列化行为与扩展点,避免在各 DTO 中重复定义公共字段。
- 设计要点:仅暴露必要字段,保持不可变或最小可变性;避免携带持久化细节。
- BaseParam
- 职责:作为请求参数的基类,集中声明校验注解、分页与排序等通用能力。
- 设计要点:与 Controller 入参解耦,便于单元测试与 Mock;支持可选字段与默认值。
classDiagram
class BaseDTO {
+ "公共字段与行为"
}
class BaseParam {
+ "公共字段与行为"
}
class UserInfoDTO
class LoginParam
UserInfoDTO --|> BaseDTO : "继承"
LoginParam --|> BaseParam : "继承"
图表来源
- BaseDTO.java
- BaseParam.java
- UserInfoDTO.java
- LoginParam.java
章节来源
- BaseDTO.java
- BaseParam.java
- UserInfoDTO.java
- LoginParam.java
MenuType 统一枚举设计
更新 项目已统一菜单类型枚举,移除了废弃的MenuTypeEnum,仅保留MenuType作为权威定义。
- MenuType
- 职责:定义权限资源树的节点类型,包括CATALOG(目录容器)、MENU(可导航页面)、BUTTON(按钮权限点)。
- 设计要点:提供fromCode工厂方法进行数据库tinyint值反查,isLegalChild方法验证父子节点关系的合法性。
- 数据库映射:CATALOG(1)、MENU(2)、BUTTON(3),对应sys_menu表的menuType字段。
classDiagram
class MenuType {
+ "CATALOG : 目录容器"
+ "MENU : 可导航页面"
+ "BUTTON : 按钮权限点"
+ "fromCode(Integer) : MenuType"
+ "isLegalChild(MenuType, MenuType) : boolean"
}
class ResourceNode {
+ "type : MenuType"
+ "fromEntity(SysMenu) : ResourceNode"
+ "toEntity() : SysMenu"
}
class SysMenu {
+ "menuType : Integer"
+ "description : String"
+ "perms : String"
+ "denyBehavior : String"
+ "status : String"
+ "apiUrl : String"
}
ResourceNode --> MenuType : "使用"
SysMenu --> MenuType : "映射"
图表来源
- MenuType.java
- ResourceNode.java
- SysMenu.java
章节来源
- MenuType.java
- ResourceNode.java
- SysMenu.java
Result 与 PageResult 统一响应封装
- Result
- 结构:包含状态码、消息、数据体三部分,保证接口返回结构一致。
- 使用:成功路径返回 data,失败路径设置错误码与消息,由全局异常处理器统一转换。
- PageResult
- 结构:包含当前页、每页大小、总记录数、总页数、数据列表等分页元信息。
- 使用:服务层返回分页数据后,通过 PageConverter 转换为 PageResult。
classDiagram
class Result {
+ "状态码"
+ "消息"
+ "数据体"
}
class PageResult {
+ "当前页"
+ "每页大小"
+ "总记录数"
+ "总页数"
+ "数据列表"
}
class ResultCodeEnum {
+ "枚举定义"
}
PageResult --> Result : "引用"
Result --> ResultCodeEnum : "使用"
图表来源
- Result.java
- PageResult.java
- ResultCodeEnum.java
章节来源
- Result.java
- PageResult.java
- ResultCodeEnum.java
DTO/Param 设计原则与字段验证规则
- 设计原则
- 单一职责:DTO 仅承载传输所需字段,Param 仅承载入参与校验。
- 最小暴露:对外只暴露必要字段,避免泄露内部实现细节。
- 可组合:通过继承 BaseDTO/BaseParam 复用公共能力。
- 字段验证规则
- 优先使用注解式校验(如非空、长度、格式),结合 AssertUtils 进行业务级断言。
- 对复杂校验逻辑在服务层集中处理,保持 Controller 简洁。
- MenuType 相关的验证使用MenuType.isLegalChild方法进行层级约束检查。
- 转换策略
- 使用 BeanCopyUtils 完成 DTO/Param/Entity 之间的属性映射。
- 对于复杂映射场景,可在服务层编写专用转换器,避免在 DTO/Param 中耦合业务逻辑。
- MenuType与Integer之间的转换使用MenuType.fromCode和getCode方法。
flowchart TD
Start(["开始"]) --> Validate["参数校验(注解/断言)"]
Validate --> Valid{"校验通过?"}
Valid --> |否| ReturnError["返回错误Result"]
Valid --> |是| Convert["对象转换(BeanCopyUtils)"]
Convert --> MenuTypeCheck["MenuType 层级验证"]
MenuTypeCheck --> Business["执行业务逻辑"]
Business --> BuildResult["构建Result/PageResult"]
BuildResult --> End(["结束"])
ReturnError --> End
图表来源
- AssertUtils.java
- BeanCopyUtils.java
- Result.java
- PageResult.java
- MenuType.java
章节来源
- AssertUtils.java
- BeanCopyUtils.java
- Result.java
- PageResult.java
- MenuType.java
领域模型扩展指导与自定义数据对象规范
- 扩展 BaseDTO/BaseParam
- 新增 DTO:继承 BaseDTO,仅添加必要字段,保持不可变性。
- 新增 Param:继承 BaseParam,集中声明校验注解,必要时提供默认值。
- 自定义数据对象
- 命名规范:以业务语义命名,避免技术实现词汇。
- 字段类型:优先使用标准类型与枚举,减少歧义。
- 序列化:如需控制 JSON 输出,仅在 DTO 上标注,不在 Param 上标注。
- 枚举使用:使用统一的领域枚举(如MenuType),避免重复定义。
- 与实体的关系
- BaseEntity/OwenedEntity 作为持久化基类,DTO/Param 不应直接继承实体基类。
- 通过 BeanCopyUtils 进行单向或双向转换,保持边界清晰。
- 枚举字段通过fromCode和getCode方法进行数据库值与枚举值的转换。
classDiagram
class BaseEntity {
+ "公共持久化字段"
}
class OwnedEntity {
+ "数据归属字段"
}
class CustomDTO
class CustomParam
class MenuType {
+ "CATALOG/MENU/BUTTON"
+ "fromCode/getCode"
}
OwnedEntity --|> BaseEntity : "继承"
CustomDTO --|> BaseDTO : "继承"
CustomParam --|> BaseParam : "继承"
CustomDTO --> MenuType : "使用"
图表来源
- BaseEntity.java
- OwnedEntity.java
- BaseDTO.java
- BaseParam.java
- MenuType.java
章节来源
- BaseEntity.java
- OwnedEntity.java
- BaseDTO.java
- BaseParam.java
- MenuType.java
依赖关系分析
- 组件内聚与耦合
- BaseDTO/BaseParam 低耦合,仅依赖基础类型与工具类。
- Result/PageResult 被各层广泛引用,需保持稳定。
- BeanCopyUtils/PageConverter 为横切工具,降低转换复杂度。
- MenuType 作为统一枚举,被ResourceNode、SysMenu等相关组件引用。
- 外部依赖
- 全局异常处理器与 Result 配合,确保错误路径一致。
- 业务模块通过继承 BaseDTO/BaseParam 复用能力。
- MenuType 消除了MenuTypeEnum的冗余,简化了依赖关系。
graph LR
BaseDTO --> BeanCopyUtils
BaseParam --> BeanCopyUtils
PageResult --> PageConverter
GlobalExceptionHandlerAdvice --> Result
Result --> ResultCodeEnum
ResourceNode --> MenuType
SysMenu --> MenuType
MenuType --> BeanCopyUtils
图表来源
- BaseDTO.java
- BaseParam.java
- BeanCopyUtils.java
- PageConverter.java
- PageResult.java
- GlobalExceptionHandlerAdvice.java
- Result.java
- ResultCodeEnum.java
- MenuType.java
- ResourceNode.java
- SysMenu.java
章节来源
- BaseDTO.java
- BaseParam.java
- BeanCopyUtils.java
- PageConverter.java
- PageResult.java
- GlobalExceptionHandlerAdvice.java
- Result.java
- ResultCodeEnum.java
- MenuType.java
- ResourceNode.java
- SysMenu.java
性能考虑
- 对象转换
- 使用 BeanCopyUtils 批量转换,避免逐字段赋值带来的样板代码与潜在性能损耗。
- 对高频转换场景,可缓存映射配置以减少反射开销。
- 分页查询
- 通过 PageConverter 将数据库分页结果转换为 PageResult,避免全量加载。
- 合理设置每页大小,避免过大导致内存压力。
- 响应封装
- Result/PageResult 尽量轻量,避免在响应中包含冗余字段。
- 对大对象返回时,考虑按需字段选择与延迟加载。
- 枚举使用
- MenuType 提供静态方法避免重复计算,提升性能。
- fromCode方法使用流式API进行高效查找。
故障排查指南
- 常见异常
- 业务异常:BusinessErrorException,表示业务规则不满足。
- 参数缺失:MissingParameterException,表示必填参数未传入。
- 权限异常:PermissionErrorException,表示权限不足。
- 资源不存在:ResourceNotExistException,表示目标资源不存在。
- 全局处理
- GlobalExceptionHandlerAdvice 捕获上述异常并转换为统一 Result,确保前端一致体验。
- 调试建议
- 在 Controller 层打印入参与关键中间结果。
- 使用 AssertUtils 快速定位参数问题。
- 检查 ResultCodeEnum 的状态码是否与前端约定一致。
- 验证 MenuType 的层级关系是否符合预期。
章节来源
- GlobalExceptionHandlerAdvice.java
- BusinessErrorException.java
- MissingParameterException.java
- PermissionErrorException.java
- ResourceNotExistException.java
- Result.java
- ResultCodeEnum.java
- MenuType.java
结论
通过 BaseDTO/BaseParam 的基类抽象、Result/PageResult 的统一封装,以及 BeanCopyUtils/PageConverter 的工具支撑,项目在领域模型层面实现了高内聚、低耦合与一致的交互契约。更新 通过统一MenuType枚举,消除了MenuTypeEnum的冗余,进一步简化了领域模型的词汇体系。遵循本文的设计原则与扩展规范,可有效提升代码可维护性与团队协作效率。
附录
- 最佳实践清单
- DTO/Param 严格分离,避免混用。
- 校验优先注解,复杂逻辑下沉至服务层。
- 转换统一使用工具类,禁止手写样板代码。
- 异常统一抛出并由全局处理器收敛。
- 使用统一的领域枚举(如MenuType),避免重复定义。
- 参考示例
- 登录参数:LoginParam 继承 BaseParam,集中声明校验注解。
- 用户信息:UserInfoDTO 继承 BaseDTO,仅暴露必要字段。
- 资源节点:ResourceNode 使用 MenuType 枚举,提供完整的CRUD操作。
- 枚举使用规范
- 使用MenuType.fromCode进行数据库值到枚举的转换。
- 使用MenuType.getCode进行枚举到数据库值的转换。
- 使用MenuType.isLegalChild验证父子节点的合法性。
章节来源
- LoginParam.java
- UserInfoDTO.java
- BaseParam.java
- BaseDTO.java
- MenuType.java
- ResourceNode.java