# TOCO平台简介 ## 平台概述 TOCO是一个基于DDD、分层设计、CQRS等理论的专业研发平台,主要目标是提供软件设计能力,设计结果可直接转换为标准格式的代码。平台覆盖从数据库到API的全链路,能够显著提升开发设计和编程效率。 ## 核心设计理念 TOCO采用严格的分层架构: - **entrance层**:API控制器层 - **service层**:服务层,处理业务逻辑 - **manager层**:管理层,处理DTO相关逻辑 - **persist层**:持久化层,处理数据访问 - **common层**:公共层,存放枚举、工具类等 技术栈:Java + SpringBoot + MyBatis-plus(读)+ Hibernate(写) ## 重要设计元素详解 ### 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、基本类型 ### 14. 应用程序接口(API) - **作用**:定义对外暴露的HTTP接口 - **URI规范**:一般为`/api/${moduleName}/xxx`格式 - **参数限制**:只能为QTO、BTO、EO、Enum、基本类型 - **返回值限制**:只能为VO、Enum、基本类型 - **分页处理**:框架自动包装返回值(code、message、data) ### 15. 流程服务(FunctionFlow) - **使用场景**: - API/RPC涉及超过3个写服务时必须使用 - 用户明确要求时使用 - **节点类型**: - 顺序节点:封装业务逻辑 - 条件节点:封装判断逻辑 - 选择节点:封装分支选择逻辑 - 开始节点:流程起点 - **设计原则**:以数据内聚为首要考虑,每个节点围绕核心写服务 ## 数据获取流程 ### DTO获取流程 1. **主键/唯一索引查询**:使用预定义方法 2. **复杂查询条件**:使用读方案 ### VO获取流程 1. **主键/唯一索引查询**:预定义方法获取DTO → convert方法转换为VO 2. **复杂查询(有对应DTO读方案)**:读方案获取DTO → convert方法转换为VO 3. **复杂查询(无对应DTO读方案)**:直接使用VO读方案 ## 接口设计最佳实践 ### 参数类型选择优先级 1. **读场景**:优先使用QTO 2. **写场景**:优先使用BTO 3. **补充参数**:基本类型、Enum、EO ### 返回值类型选择 1. **RPC返回值**:DTO、Enum、基本类型 2. **API返回值**:VO、Enum、基本类型 ### 绝对禁止的用法 - DTO、VO不能作为参数类型 - QTO、BTO不能作为返回值类型 - Service层不能返回VO - VO不能作为RPC返回值 ## 代码修改指南 ### 推荐修改的位置 1. **BO类**:`validateAggregate`或`valid`方法中添加业务校验 2. **Converter类**:自定义字段的数据获取逻辑 3. **Service类**:业务逻辑实现 4. **API Controller**:接口实现逻辑 ### 禁止修改的内容 1. 带有`@AutoGenerated(locked=true)`的类和方法 2. DTO、VO的结构定义 3. Manager类的系统生成方法 4. Mapper类的结构定义 ## 并发控制最佳实践 在处理先读后更新的场景时,为避免并发引起的数据脏写: 1. **写方案中使用incr字段** 2. **BoService中添加校验**:如`if(userBo.getBalance() >= 0)` 3. **聚合校验**:在BO的业务不变性校验中添加约束条件 ## 项目结构导航 标准查找流程: - **API查找**:`modules/{模块名}/entrance/web/controller/` - **DTO查找**:`modules/{模块名}/manager/dto/` - **Service查找**:`modules/{模块名}/service/` - **数据层查找**:`modules/{模块名}/persist/` ## 重要注意事项 1. **跨模块调用**:必须通过订阅RPC,使用RpcAdapter进行调用 2. **变量命名**:RpcAdapter注入时变量名必须是类名首字母小写 3. **自定义字段逻辑**:必须在BaseConverter的Map转换方法中实现 4. **读写分离**:读操作使用MyBatis-plus,写操作使用Hibernate 5. **严格分层**:各层职责明确,不能越层调用