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.
 
 
 
 
 

25 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) - [ResourceServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/ResourceServiceImpl.java)

更新摘要

所做更改

  • 更新了菜单类型定义部分,反映移除了冗余的MenuTypeEnum枚举,统一使用MenuType作为节点类型定义的唯一来源
  • 新增了MenuType枚举的详细分析,包括其设计模式和层级约束逻辑
  • 更新了ResourceNode DTO中MenuType的使用示例
  • 增强了领域模型扩展指导中关于枚举设计的最佳实践

目录

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

简介

本文件面向领域模型与数据契约,系统性说明 BaseDTO、BaseParam 的基类设计与继承关系,统一响应 Result 与分页结果 PageResult 的结构与用法,阐述 DTO 与 Param 的设计原则、字段验证规则与转换策略,并给出领域模型的扩展指导与自定义数据对象的创建规范。目标是帮助开发者在 CRM 后端项目中以一致、可维护的方式定义数据传输对象、参数对象以及统一的接口响应格式。

项目结构

本项目采用多模块组织,领域模型相关的基础类型集中在 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
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["service/impl/ResourceServiceImpl"]
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
  • ResourceServiceImpl.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
  • ResourceServiceImpl.java

核心组件

  • BaseDTO:所有数据传输对象的基类,提供统一的序列化、审计或扩展字段约定,便于跨层传递数据。
  • BaseParam:所有请求参数的基类,集中承载校验注解、分页与排序等通用能力,简化 Controller 入参定义。
  • Result:统一响应封装,包含状态码、消息与数据体,确保前后端交互一致性。
  • PageResult:分页结果封装,聚合页码、总数、列表数据等分页元信息。
  • BeanCopyUtils:对象拷贝工具,用于 DTO/Param/Entity 之间的属性映射与转换。
  • PageConverter:分页转换工具,将框架分页对象转换为 PageResult。
  • AssertUtils:断言工具,用于快速进行参数合法性校验。
  • GlobalExceptionHandlerAdvice:全局异常处理器,将业务异常转换为统一 Result。
  • MenuType:权限资源树节点类型枚举,定义了CATALOG、MENU、BUTTON三种节点类型及其层级约束。

章节来源

  • 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 相互转换。

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-->>Controller : "业务结果(DTO/Entity)"
Controller->>Response : "封装为Result/PageResult"
Response-->>Client : "JSON 响应"

图表来源

  • GlobalExceptionHandlerAdvice.java
  • BeanCopyUtils.java
  • Result.java
  • PageResult.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工厂方法进行DB值到枚举的转换,isLegalChild方法实现层级约束验证。
    • 层级约束:CATALOG只能包含MENU,MENU只能包含BUTTON,BUTTON是叶子节点。
classDiagram
class MenuType {
+ "CATALOG : 菜单分组"
+ "MENU : 菜单页面"
+ "BUTTON : 按钮/权限点"
+ "fromCode(Integer) : MenuType"
+ "isLegalChild(MenuType, MenuType) : boolean"
}
class ResourceNode {
+ "type : MenuType"
+ "fromEntity(SysMenu) : ResourceNode"
+ "toEntity() : SysMenu"
}
MenuType <.. ResourceNode : "使用"

图表来源

  • MenuType.java
  • ResourceNode.java

章节来源

  • MenuType.java
  • ResourceNode.java
  • ResourceServiceImpl.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 简洁。
  • 转换策略
    • 使用 BeanCopyUtils 完成 DTO/Param/Entity 之间的属性映射。
    • 对于复杂映射场景,可在服务层编写专用转换器,避免在 DTO/Param 中耦合业务逻辑。
flowchart TD
Start(["开始"]) --> Validate["参数校验(注解/断言)"]
Validate --> Valid{"校验通过?"}
Valid --> |否| ReturnError["返回错误Result"]
Valid --> |是| Convert["对象转换(BeanCopyUtils)"]
Convert --> Business["执行业务逻辑"]
Business --> BuildResult["构建Result/PageResult"]
BuildResult --> End(["结束"])
ReturnError --> End

图表来源

  • AssertUtils.java
  • BeanCopyUtils.java
  • Result.java
  • PageResult.java

章节来源

  • AssertUtils.java
  • BeanCopyUtils.java
  • Result.java
  • PageResult.java

领域模型扩展指导与自定义数据对象规范

  • 扩展 BaseDTO/BaseParam
    • 新增 DTO:继承 BaseDTO,仅添加必要字段,保持不可变性。
    • 新增 Param:继承 BaseParam,集中声明校验注解,必要时提供默认值。
  • 自定义数据对象
    • 命名规范:以业务语义命名,避免技术实现词汇。
    • 字段类型:优先使用标准类型与枚举,减少歧义。
    • 序列化:如需控制 JSON 输出,仅在 DTO 上标注,不在 Param 上标注。
  • 与实体的关系
    • BaseEntity/OwenedEntity 作为持久化基类,DTO/Param 不应直接继承实体基类。
    • 通过 BeanCopyUtils 进行单向或双向转换,保持边界清晰。
  • 枚举设计最佳实践
    • 单一来源:避免重复定义相似枚举,如MenuTypeEnum和MenuType的统一。
    • 工厂方法:提供fromCode等方法简化DB值到枚举的转换。
    • 业务逻辑:在枚举中封装相关的业务规则,如层级约束验证。
classDiagram
class BaseEntity {
+ "公共持久化字段"
}
class OwnedEntity {
+ "数据归属字段"
}
class CustomDTO
class CustomParam
class MenuType {
+ "节点类型定义"
+ "层级约束验证"
}
OwnedEntity --|> BaseEntity : "继承"
CustomDTO --|> BaseDTO : "继承"
CustomParam --|> BaseParam : "继承"
MenuType <.. CustomDTO : "使用"

图表来源

  • 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和相关服务类引用。
  • 外部依赖
    • 全局异常处理器与 Result 配合,确保错误路径一致。
    • 业务模块通过继承 BaseDTO/BaseParam 复用能力。
graph LR
BaseDTO --> BeanCopyUtils
BaseParam --> BeanCopyUtils
PageResult --> PageConverter
GlobalExceptionHandlerAdvice --> Result
Result --> ResultCodeEnum
MenuType --> ResourceNode
ResourceNode --> ResourceServiceImpl

图表来源

  • BaseDTO.java
  • BaseParam.java
  • BeanCopyUtils.java
  • PageConverter.java
  • PageResult.java
  • GlobalExceptionHandlerAdvice.java
  • Result.java
  • ResultCodeEnum.java
  • MenuType.java
  • ResourceNode.java
  • ResourceServiceImpl.java

章节来源

  • BaseDTO.java
  • BaseParam.java
  • BeanCopyUtils.java
  • PageConverter.java
  • PageResult.java
  • GlobalExceptionHandlerAdvice.java
  • Result.java
  • ResultCodeEnum.java
  • MenuType.java
  • ResourceNode.java
  • ResourceServiceImpl.java

性能考虑

  • 对象转换
    • 使用 BeanCopyUtils 批量转换,避免逐字段赋值带来的样板代码与潜在性能损耗。
    • 对高频转换场景,可缓存映射配置以减少反射开销。
  • 分页查询
    • 通过 PageConverter 将数据库分页结果转换为 PageResult,避免全量加载。
    • 合理设置每页大小,避免过大导致内存压力。
  • 响应封装
    • Result/PageResult 尽量轻量,避免在响应中包含冗余字段。
    • 对大对象返回时,考虑按需字段选择与延迟加载。
  • 枚举使用
    • MenuType等枚举类型在内存中共享,避免重复实例化。
    • 使用fromCode方法进行枚举查找,避免字符串比较的性能开销。

[本节为通用性能建议,不直接分析具体文件]

故障排查指南

  • 常见异常
    • 业务异常:BusinessErrorException,表示业务规则不满足。
    • 参数缺失:MissingParameterException,表示必填参数未传入。
    • 权限异常:PermissionErrorException,表示权限不足。
    • 资源不存在:ResourceNotExistException,表示目标资源不存在。
  • 全局处理
    • GlobalExceptionHandlerAdvice 捕获上述异常并转换为统一 Result,确保前端一致体验。
  • 调试建议
    • 在 Controller 层打印入参与关键中间结果。
    • 使用 AssertUtils 快速定位参数问题。
    • 检查 ResultCodeEnum 的状态码是否与前端约定一致。
  • 枚举相关问题
    • 检查MenuType.fromCode()是否能正确解析DB存储的值。
    • 验证层级约束isLegalChild()的逻辑是否符合业务需求。

章节来源

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

结论

通过 BaseDTO/BaseParam 的基类抽象、Result/PageResult 的统一封装,以及 BeanCopyUtils/PageConverter 的工具支撑,项目在领域模型层面实现了高内聚、低耦合与一致的交互契约。移除了冗余的MenuTypeEnum枚举,统一使用MenuType作为节点类型定义的唯一来源,进一步提升了代码的一致性和可维护性。遵循本文的设计原则与扩展规范,可有效提升代码可维护性与团队协作效率。

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

附录

  • 最佳实践清单
    • DTO/Param 严格分离,避免混用。
    • 校验优先注解,复杂逻辑下沉至服务层。
    • 转换统一使用工具类,禁止手写样板代码。
    • 异常统一抛出并由全局处理器收敛。
    • 枚举设计遵循单一来源原则,避免重复定义。
  • 参考示例
    • 登录参数:LoginParam 继承 BaseParam,集中声明校验注解。
    • 用户信息:UserInfoDTO 继承 BaseDTO,仅暴露必要字段。
    • 菜单类型:MenuType 定义节点类型及层级约束,ResourceNode 使用MenuType作为类型字段。

章节来源

  • LoginParam.java
  • UserInfoDTO.java
  • BaseParam.java
  • BaseDTO.java
  • MenuType.java
  • ResourceNode.java