9.7 KiB
9.7 KiB
TOCO平台简介
平台概述
TOCO是一个基于DDD、分层设计、CQRS等理论的专业研发平台,主要目标是提供软件设计能力,设计结果可直接转换为标准格式的代码。平台覆盖从数据库到API的全链路,能够显著提升开发设计和编程效率。
核心设计理念
TOCO采用严格的分层架构:
- entrance层:API控制器层
- service层:服务层,处理业务逻辑
- manager层:管理层,处理DTO相关逻辑
- persist层:持久化层,处理数据访问
- common层:公共层,存放枚举、工具类等
技术栈:Java + SpringBoot + MyBatis-plus(读)+ Hibernate(写)
##平台能力边界说明: TOCO的设计模型旨在规范系统结构、统一数据契约与接口形态,自动生成约80%的基础代码框架(如控制器签名、DTO转换、读写方案执行器等)。 然而,业务行为逻辑(如条件判断、动态路由、状态流转、异常处理、多源聚合、性能优化路径等)无法由设计自动推导或生成,必须由人工编码实现。 因此: 设计元素仅表达“系统能做什么”(接口定义、数据结构、依赖关系); **代码实现才是“系统正在做什么”**的唯一真实来源; 设计与代码之间存在不可逾越的行为鸿沟——设计不记录实现细节,代码不反馈回设计; 任何对系统行为的分析、影响评估或变更决策,都必须同时考察结构层面的设计信息与行为层面的代码实现,二者缺一不可。
重要设计元素详解
1. 模块(Module)
- 作用:系统领域的具体细分,映射为Java工程中的module
- 命名规则:小写英文字母+下划线,如
meeting、user_detail,全局唯一 - 代码结构:每个Module生成独立的Java Module,采用entrance、service、manager、persist、common分层
2. 枚举(Enum)
- 作用:表达常量值集合,可被其他模块使用
- 命名规则:以
_enum结尾,全局唯一 - 生成位置:
**.common.enums包路径下 - 修改建议:不建议修改
3. 值对象(EO)
- 作用:POJO对象结构,可被其他模块使用
- 命名规则:以
_eo结尾,全局唯一 - 字段限制:只能为基本类型、EO、Enum类型
- 生成位置:
**.persist.eo包路径下
4. 实体关系(Entity)
- 作用:对应数据库表,定义实体间的外键依赖关系
- 生成产物:
- 结构定义类:
**.persist.dos - Mapper类:
**.persist.mapper.mybatis - Dao接口:
**.persist.mapper - Dao实现:
**.persist.mapper
- 结构定义类:
5. 聚合对象(BO)
- 核心概念:封装一组密切关联的实体,以聚合根为起点,按层级关系组装其他实体
- 重要特性:
- 提供数据操作入口和内存一致性视图
- 只能在单一模块中组合
- 一个实体只能属于一个聚合对象
- 生成位置:
**.manager.bo包路径下 - 修改建议:建议修改BO中的
validateAggregate或valid方法进行业务不变性校验
6. 数据传输对象(DTO)
- 核心概念:以某个Entity为基础,通过外键关系关联多个Entity的数据结构
- 分类:
- BaseDTO:每个Entity自动生成一个,包含Entity全部字段
- 普通DTO:派生自BaseDTO,可增加扩展字段或自定义字段
- 字段扩展方式:
- 正向替换:将外键字段替换为对应Entity的DTO对象
- 反向注入:在当前Entity中注入其他Entity的DTO对象或列表
- 预定义方法:TOCO自动为每个DTO生成基于唯一索引的RPC方法
- 生成产物:
- 结构定义:
**.manager.dto - Manager:
**.manager - Converter:
**.manager.converter
- 结构定义:
7. 视图对象(VO)
- 作用:用于视图层与前端数据传输,作为HTTP API返回值
- 派生关系:通常派生自BaseDTO或其他DTO
- 分类:
- 根VO:需要创建,有uuid标识
- 子VO:自动创建,附属于根VO
- 与DTO区别:VO更接近UI展示,可裁剪冗余字段;DTO更接近数据模型,复用性强
- 转换方法:
- 基础转换:
convertTo${VoName} - 带数据拼装:
convertAndAssembleData
- 基础转换:
8. 查询对象(WO)
- 作用:表达以某Entity为基础通过外键关系关联多个Entity的查询结构
- 用途:作为ReadPlan的查询上下文使用
9. 读方案(ReadPlan)
- 作用:描述如何基于查询对象从数据库获取DTO/VO列表数据
- 核心能力:
- 复杂查询条件组合
- 数据拼装和过滤
- 分页和排序
- 能力边界:
- 支持等值、模糊、范围、包含查询
- 支持列表属性过滤
- 不支持复杂统计和聚合计算
- 使用原则:根据主键或唯一索引查询时,优先使用DTO预定义方法,其他复杂查询使用读方案
- 生成产物:自动生成RPC方法和对应的QTO
10. 写方案(WritePlan)
- 重要限制:一个写方案只能操作一个聚合内的表,无法跨聚合操作
- 操作类型:
CREATE:创建单个实体UPDATE:更新单个实体DELETE:删除单个实体CREATE_ON_DUPLICATE_UPDATE:创建或更新单个实体FULL_MERGE:批量更新列表数据(全量替换)PARTIAL_MERGE:批量更新列表数据(部分更新)
- 生成产物:自动生成RPC方法和对应的BTO
11. 查询传输对象(QTO)
- 作用:读方案的查询参数结构
- 使用场景:作为API参数,禁止用作写参数
12. 业务变更传输对象(BTO)
- 作用:写方案的参数结构
- 特点:树形结构,最外层为聚合根
- 使用场景:作为API参数,禁止用作查询参数
13. 服务层方法(RPC)
- 分类:
- 公开RPC:可被其他模块订阅调用
- 非公开RPC:只能被当前模块调用
- 创建方式:
- DTO创建后自动生成
- 读方案自动生成
- 写方案自动生成
- 手动创建自定义RPC
- 参数限制:只能为QTO、BTO、Enum、基本类型
- 返回值限制:只能为DTO、Enum、基本类型
- 存储特点: TOCO只存储RPC的方法签名,不存储执行逻辑。了解API内部具体实现需阅读对应代码
14. 应用程序接口(API)
- 作用:定义对外暴露的HTTP接口
- URI规范:一般为
/api/${moduleName}/xxx格式 - 参数限制:只能为QTO、BTO、EO、Enum、基本类型
- 返回值限制:只能为VO、Enum、基本类型
- 分页处理:框架自动包装返回值(code、message、data)
- 存储特点: TOCO只存储API的URI和方法签名,不存储执行逻辑。了解API内部具体实现需阅读对应代码
15. 流程服务(FunctionFlow)
- 使用场景:
- API/RPC涉及超过3个写服务时必须使用
- 用户明确要求时使用
- 节点类型:
- 顺序节点:封装业务逻辑
- 条件节点:封装判断逻辑
- 选择节点:封装分支选择逻辑
- 开始节点:流程起点
- 设计原则:以数据内聚为首要考虑,每个节点围绕核心写服务
-
领域消息 (DomainMessage) 可以监听聚合对象实体的创建、删除、更新事件;通过事件驱动的方式实现异步解耦;也是一种跨模块通信的方式;消息驱动的一种实现;
-
普通消息 (CommonMessage) 自定义字段,自持事务、延时特性;是对领域消息的补充
数据获取流程
DTO获取流程
- 主键/唯一索引查询:使用预定义方法
- 复杂查询条件:使用读方案
VO获取流程
- 主键/唯一索引查询:预定义方法获取DTO → convert方法转换为VO
- 复杂查询(有对应DTO读方案):读方案获取DTO → convert方法转换为VO
- 复杂查询(无对应DTO读方案):直接使用VO读方案
接口设计最佳实践
参数类型选择优先级
- 读场景:优先使用QTO
- 写场景:优先使用BTO
- 补充参数:基本类型、Enum、EO
返回值类型选择
- RPC返回值:DTO、Enum、基本类型
- API返回值:VO、Enum、基本类型
绝对禁止的用法
- DTO、VO不能作为参数类型
- QTO、BTO不能作为返回值类型
- Service层不能返回VO
- VO不能作为RPC返回值
代码修改指南
推荐修改的位置
- BO类:
validateAggregate或valid方法中添加业务校验 - Converter类:自定义字段的数据获取逻辑
- Service类:业务逻辑实现
- API Controller:接口实现逻辑
禁止修改的内容
- 带有
@AutoGenerated(locked=true)的类和方法 - DTO、VO的结构定义
- Manager类的系统生成方法
- Mapper类的结构定义
并发控制最佳实践
在处理先读后更新的场景时,为避免并发引起的数据脏写:
- 写方案中使用incr字段
- BoService中添加校验:如
if(userBo.getBalance() >= 0) - 聚合校验:在BO的业务不变性校验中添加约束条件
项目结构导航
标准查找流程:
- API查找:
modules/{模块名}/entrance/web/controller/ - DTO查找:
modules/{模块名}/manager/dto/ - Service查找:
modules/{模块名}/service/ - 数据层查找:
modules/{模块名}/persist/
重要注意事项
- 跨模块调用:必须通过订阅RPC,使用RpcAdapter进行调用
- 变量命名:RpcAdapter注入时变量名必须是类名首字母小写
- 自定义字段逻辑:必须在BaseConverter的Map转换方法中实现
- 读写分离:读操作使用MyBatis-plus,写操作使用Hibernate
- 严格分层:各层职责明确,不能越层调用