diff --git a/llms-full.txt b/llms-full.txt index f506c93..9fd2f6f 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -463,9 +463,130 @@ DateTime endTime; //会议结束时间 * 如UserDetailVo、UserDetailVoConverter(包含convertToUserDetailVo、convertToUserDetailVoList、convertToUserDetailVoMap、convertAndAssembleData、convertAndAssembleDataList方法) - **修改建议:** - 建议在Converter中进行代码扩展,不建议修改结构定义文件。其中VO的**自定义字段**由于不直接派生自DTO,所以一般会对应取数逻辑代码。通常如果涉及到数据获取、计算和拼装,批量处理的性能最好,所以自定义字段对应的代码位置**必须**放在Converter的**Map**基础转换方法convertTo${VoName}Map中,批量取数组装,如UserVoConverter.convertToUserVoMap - - -#### **2.8 读方案 (ReadPlan)** +#### **2.8 查询对象(WO)** +- **定义与用途:** 在TOCO中,WO表达某个Entity为基本,通过外键关系不断关联多个Entity的数据结构。WO还隐式表达了数据的取数拼装,这种拼装符合外键关系. WO作为ReadPlan的查询上下文使用,所以在创建ReadPlan之前需要先创建WO对象。在理解一个ReadPlan的语义的时候需要以WO作为上下文。 +- **查询对象案设计元素的表达** + - 以json格式表达,json schema 定义如下 + ```json + { + "type": "object","description": "查询对象定义", "required": ["name","fromEntity"], + "properties": { + "name": {"type": "string", "description": "查询对象名称,用英语表达,单词之间下划线分割,长度补超过32个字符"}, + "uuid": {"type": "string", "description": "查询对象uuid, 在更新的时候必须传递(只有根节点必须传递),创建的时候不传递"}, + "moduleName": {"type": "string", "description": "查询对象所属模块名称,在创建的时候必须传递"}, + "fromEntity": {"type": "string", "description": "查询对象对应的实体"}, + "expandList": { + "type": "array", "description": "正向扩展列表", + "items": + { + "type": "object","description": "正向扩展字段定义","required": ["field","wo","fieldName"], + "properties": { + "field": {"type": "string", "description": "指定fromEntity的扩展字段,必须是fromEntity的外键字段"}, + "wo": {"$ref": "#"}, + "fieldName": {"type": "string", "description": "扩展出来的字段名称"} + } + } + }, + "reverseExpandList": { + "type": "array", "description": "反向扩展列表", + "items": + { + "type": "object","description": "反向扩展字段定义","required": ["field","wo","fieldName"], + "properties": { + "field": {"type": "string", "description": "指定fromEntity的扩展字段,必须是fromEntity的外键字段"}, + "wo": {"$ref": "#"}, + "fieldName": {"type": "string", "description": "扩展出来的字段名称"} + } + } + } + } + } + ``` +- **如何创建/生成:** +- **关键配置:** Wo中的字段分为三种:a.继承Entity的字段,和Entity的字段类型一样;b.扩展字段,含正向替换和反向注入字段,类型为WO或List; +- **字段扩展方式:**TOCO定义了一个WO组装方法,适用于WO通过外键关系替换/注入对应Entity的信息,对象化表达有外键关系的Entity信息。只要存在外键关系且满足以下条件即可扩展:a.对于正向替换:当前实体存在指向其他实体的外键字段;b.对于反向注入:其他实体存在指向当前实体的外键字段。 + 例如:有两个Entity + ``` + MeetingRoom{ //会议室 + Long id;// 会议室id,主键 + String name;// 会议室名称 + } + Meeting { //会议 + Long id;// 会议id,主键 + Long roomid; //占用的会议室id,到MeetingRoom的外键,n:1关系 + Long backupRoomid; //备用的会议室id,到MeetingRoom的外键,n:1关系 + String title; //会议标题 + DateTime startTime; //会议开始时间 + DateTime endTime; //会议结束时间 + } + ``` +其中Meeting和MeetingRoom是n:1关系。即多个会议室会占用同一个会议室。 +当组装对象以某Entity为根时,那么首先它将拥有和该Entity一样的数据结构,并将通过下面的“正向替换”,“反向注入”的行为,递归的将多个互相之间有外键关系的Entity的信息组装到该组装对象中。 +定义“正向替换”这个行为,选定一个表,这张表存在到另外一张表的一个或多个外键。选择和需求相关的具体的外键属性,将该外键属性替换为另一张表为根的组装对象。这样就可以获取基于某些外键且包含另一张表更详细的属性数据。 +例如:需要会议和其占用会议室时,将Meeting表中的roomid外键替换为以MeetingRoom为根的组装对象,而backupRoomid对应的候选会议室具体信息和本需求无关,不做任何替换。如下: + ``` + MeetingWithRoomWo { + Long id;// 会议id + MeetingRoomWo room { //正向替换该会议用的会议室信息,是一个以会议室为根的对象 + Long id; //会议室ID + String name;// 会议室名称 + } + Long backupRoomid; // 不做变化 + String title; //会议标题 + DateTime startTime; //会议开始时间 + DateTime endTime; //会议结束时间 + } + ``` +又例如:需要会议和其候选会议室时,将Meeting表中的backupRoomid进行正向替换。 +又例如:需要会议,且即需要其占用会议室,也需要候选会议室时,将Meeting表中的roomid,backupRoomid都进行正向替换。 +同时TOCO还定义了“反向注入”这个行为,选定一个表,如果有另外的表到前表有外键,选择和需求相关的具体的外键属性在选定表中增加一个以另外表为根的组合对象(当外键关系是1:1时)或者组合对象的列表(当外键关系是n:1时)。需求是:“获取会议室,和占用它的会议信息”,需要选定MeetingRoom,那么基于另外的表Meeting中存在字段roomid,为到MeetingRoom的n:1关系外键。可以将List反向注入到MeetingRoom中,最终生成一个以Meeting为根的组装对象,生成: + ``` + MeetingRoomWithMeetingWo { + Long id;// 会议室id + String name;// 会议室名称 + List meetingList { //反向注入的用该会议室的会议信息,是以会议为根的对象 + Long id;// 会议id + String title; //会议标题 + DateTime startTime; //会议开始时间 + DateTime endTime; //会议结束时间 + } + } + ``` +这种“正向替换”和“反向注入”可以按需递归调用,去将多个互相之间有外键关系的对象组装成最终对象。例如,还有另外一张表MeetingAgenda到Meeting有n:1的外键,那么如果我要去组装以Meeting开始,包含MeetingRoom, MeetingAgenda的查询对象,首先发现MeetingRoom是可以正向扩展到Meeting的,并且可以反向注入MeetingAgenda +- meeting_with_room_and_agenda_wo +```json +{ + "wo": { + "uuid": null, + "name": "meeting_with_room_and_agenda_wo", + "description": "会议详情,包含会议室信息,以及其中的会议列表", + "fromEntity": "meeting", + "expandList": [ + { + "field": "room_id", + "fieldName": "meeting_room", + "wo": { + "name": "meeting_room_wo", + "fromEntity": "meeting_room", + "description": "会议室信息" + } + } + ], + "reverseExpandList": [ + { + "field":"meeting_id", + "filedName": "meeting_agenda_list", + "wo": { + "fromEntity": "meeting_agenda", + "name": "meeting_agenda_wo", + "description": "会议议程信息" + } + } + ] + } +} +``` +#### **2.9 读方案 (ReadPlan)** - **定义与用途:** 在TOCO中,读方案描述了一种数据库查询方案,查询条件为一个面向对象的查询语句,其中可以包含存在外键关系的多个实体的字段(如age=18 and name like #nameLike and school.name like #schoolNameLike,其中以#开头的是自定义参数,会自动生成一个QTO结构,由查询调用方动态传入),结果为符合查询条件的**一种**DTO或VO列表。读方案内部会将该面向对象的查询条件转化为复杂的join sql语句,来实现对数据库的查询,以及返回的复杂DTO和VO数据的组装。读方案可以指定其分页方式(不分页、页码分页、瀑布流分页),以及是否生成计数方法(用于返回符合条件的记录数量)。 - **使用建议:** 如果查询条件只有主键,则建议使用预定义的getBy${PrimaryKey}或getBy${PrimaryKey}s方法来获取DTO(参照DTO的**预定义方法**)或VO(参照**复杂嵌套VO获取流程**),不建议使用读方案。非主键查询或多条件查询建议使用读方案。 - **关键配置:** 名称(小写字母+下划线,不要以read_plan结尾)、返回结构(DTO/VO,一个读方案**不能**同时返回多种DTO或VO)、查询条件的自然语言描述、是否生成计数方法、排序字段(如果选择不分页,则不需要) @@ -676,7 +797,7 @@ DateTime endTime; //会议结束时间 * **生成产物:** 在Service层生成一个Java类 * **命名规则:** 类名以Qto结尾(${ReadPlanName}Qto) * **类路径:** 位于 ```**.persist.qto```包路径下 - * **职责:** 读方案的查询参数结构 + * **职责:** 读方案的查询参数结构,通常可作为API的参数,API接收到参数后可直接透传给内部的RPC进行调用 * **唯一标识符位置:** 其对应的唯一标志在类注解@AutoGenerated中指定,uuid规则: ${ReadPlan在TOCO中的uuid}|QTO|DEFINITION - **Dao** - **生成产物:** 在Dao层生成一个Java类 @@ -698,12 +819,12 @@ DateTime endTime; //会议结束时间 * 根据用户名称查询用户列表返回UserDTO,则生成UserNameQto、UserNameQtoService、UserNameQtoDao、UserNameQueryService; UserNameQueryService调用UserNameQtoService,UserNameQtoService调用UserNameQtoDao - **修改建议:** - 如果有对结果的数据二次处理,建议在QueryService和QueryExecutor中进行代码扩展,不建议修改QTO文件 -#### **2.9 查询传输对象(QTO)** +#### **2.10 查询传输对象(QTO)** - **定义与用途:** 在TOCO中,QTO为读方案的查询参数结构,每个读方案会对应一个QTO,写方案调用方按照QTO的结构向读方案生成的RPC方法传入需要查询的实体字段值,完成对数据库的查询 - **如何创建/生成:** 在创建读方案后,TOCO会自动生成QTO作为该读方案传入的查询参数结构,无需单独创建 - **关键配置:** 名称(${ReadPlanNameQto},驼峰展示),查询字段列表(如idIs,nameLike, schoolNameLike等) - **与API的关系:** QTO通常可作为API的参数,API接收到参数后可直接透传给内部的RPC进行调用 -#### **2.10 写方案 (WritePlan)** +#### **2.11 写方案 (WritePlan)** - **定义与用途:** TOCO针对写场景定义了一种写方案,所有对数据库的写操作都只能通过写方案实现。写方案包含了对数据库表的写操作。每个写方案只能操作一个聚合内部的表,同时对一个聚合内表的操作尽量合并至一个写方案中(根据复用性、内聚性等方面具体情况具体分析)。注意写方案可以一次操作聚合内的多张表,如location和storey是同一个聚合,并且location和storey是**1:N**关系,location是父对象(聚合根),storey是子对象,那么我们可以创建一个写方案,同时更新单个聚合根location中的信息,以及操作其下的子表storey**列表**信息,如新增、删除、修改storey等;也可以创建一个写方案单独更新单个子表storey对象信息。 - **关键配置:** 名称(小写字母+下划线,不要以write_plan结尾),操作的聚合,聚合内的实体和字段,对每个实体的操作类型:CREATE(创建**单个**实体),UPDATE(更新**单个**实体), DELETE(删除**单个**实体), CREATE_ON_DUPLICATE_UPDATE(创建或者更新**单个**实体),FULL_MERGE( 批量更新**列表**数据,根据传入的列表数据,一条一条执行CREATE_ON_DUPLICATE_UPDATE的操作;并且删除掉老的列表中不在传入列表数据中的部分), PARTIAL_MERGE(批量更新**列表**数据,根据传入的列表数据,一条一条执行) - **与RPC的关系:** 对于每一个写方案,TOCO会自动生成一个RPC方法,其参数为写方案对应的BTO,返回值为本次操作的聚合根实体的主键值,内部只实现了对当前聚合的数据库操作 @@ -822,7 +943,7 @@ DateTime endTime; //会议结束时间 ] } ``` -- **代码产物和修改建议** +- **代码产物和修改建议** - **Service:** * **生成产物:** 在对应的聚合服务BoService里生成一个函数 * **函数命名规则:** 和写方案同名 @@ -844,7 +965,7 @@ DateTime endTime; //会议结束时间 - **修改建议:** - 不能修改BaseBoService中的函数,不建议修改BTO文件。建议在BOService中进行手动代码扩展,处理可能被复用的修改前后的逻辑,如修改数据库的前后值对比、或常被复用的校验逻辑(业务不变性校验逻辑除外)、需要经常在一个事务内执行的其他写操作等。 -#### **2.11 业务变更传输对象(BTO)** +#### **2.12 业务变更传输对象(BTO)** - **定义与用途:** 在TOCO中,BTO为写方案自动生成的参数结构,每个写方案会生成一个BTO。BTO为写方案选定的操作实体根据关系形成的树形集合,最外层为聚合根。写方案调用方按照BTO的结构向写方案生成的RPC方法传入需要操作的实体字段值,完成对数据库的写操作 - **如何创建/生成:** 在创建写方案后,TOCO会自动生成一个BTO作为该写方案传入的参数结构,无需通过TOCO创建。 - **关键配置:** 名称(${WritePlanName}Bto,驼峰展示),嵌套的树形实体和字段列表,BTO内部的字段全部都来自Entity。以下为一个示例: @@ -859,7 +980,7 @@ DateTime endTime; //会议结束时间 } ``` - **与API的关系:** BTO通常可作为API的参数,API接收到参数后可直接透传给内部的RPC进行调用 -#### **2.12 服务层方法 (RPC)** +#### **2.13 服务层方法 (RPC)** - **定义与用途:** 在TOCO中,RPC为服务层的方法。RPC按照可见性可以分为两种,一种是公开RPC,可以被其他模块订阅,订阅后可以通过RPC适配器进行调用;另一种是非公开RPC,只能被当前模块调用。非公开RPC可以被公开,从而被其他模块订阅并调用 - **如何创建/生成:** RPC有4种创建方式:a.DTO创建后会自动创建RPC,RPC的公开性与DTO的公开性保持一致;b.返回DTO的读方案会根据分页情况、以及是否生成计数函数的配置自动生成非公开的RPC c.写方案创建后会自动生成非公开的RPC d.如果上述三种RPC无法满足需求,则可以通过TOCO创建自定义RPC完整指定功能,需指定具体的参数和返回值以及公开性等。 - **优先复用:** 当用户需要创建一个RPC时,如果用户有明确要求创建的方式,则按照用户的要求来创建。如果没有明确要求,则通常先判断是否可以通过创建读方案、写方案、DTO来使TOCO自动创建出对应的RPC,最后再考虑通过TOCO创建自定义RPC @@ -891,7 +1012,7 @@ requestParams为请求参数列表,response为返回结构,requestParams中 - **代码产物和修改建议** - **生成代码:** RPC会在service层中生成类文件及实现函数,包含DTO自动生成的RPC如UserDtoService.getById或UserBaseDtoService.getById、读写方案自动生成的RPC如UserDtoQueryService.queryByListQto、UserBOService.createUser、自定义RPC如UserCustomService.customMethod。特别注意公开的RPC才可被其他模块使用,RPC被订阅后会生成RpcAdapter适配器,其他模块通过RpcAdapter才可调用该方法。如Order模块订阅了User模块的UserDtoService.getById,则会在Order模块中生成UserDtoServiceInOrderRpcAdapter.getById方法,Order模块中的代码必须通过@Resource private UserDtoServiceInOrderRpcAdapter userDtoServiceInOrderRpcAdapter;注入适配器后才可进行方法调用 - **修改建议:** 建议修改RPC方法,不建议修改RPC方法签名、适配器中的内容 -#### **2.13 应用程序接口 (API)** +#### **2.14 应用程序接口 (API)** - **定义与用途:** 在TOCO中,API用于定义对外暴露的HTTP接口 - **如何创建/生成:** API一般为通过TOCO创建,需指定具体的参数和返回值等 - **关键配置:** uri(加粗展示,一般为/api/${moduleName}/xxx,如/api/user/create。如果用户有特殊命名规则的话以用户要求为准)、类名(以Controller结尾)、方法名、请求参数、返回值 @@ -927,7 +1048,7 @@ requestParams为请求参数列表,response为返回结构,requestParams中 - **代码产物和修改建议** - **生成代码:** API会在entrance层生成Controller以及对应的API方法 - **修改建议:** 建议修改API方法的实现内容,不建议修改API方法签名、URI -#### **2.14 流程服务(FunctionFlow)** +#### **2.15 流程服务(FunctionFlow)** - **定义与用途:** TOCO针对复杂业务拆解,定义了流程服务,把一个复杂的业务过程,根据业务逻辑的内聚性,合并逻辑功能,把流程分解成流程节点,最终构造出一个类似工作流的逻辑流程;最终实现复杂业务流程分解,提升代码的可维护性。TOCO内嵌了流程引擎,在Function_Flow生成代码后,可以在流程引擎中执行 - **何时使用:** - 如果一个API/RPC中涉及的写服务超过3个,则推荐使用流程服务