系统架构与分支规范
2026/8/27 20:17:24 网站建设 项目流程
--- trigger: always_on --- # 后端架构与分支规范 ## 分层架构 - 严格遵守 Controller → Service → Store → Mapper 的分层原则 - Controller层:负责API映射,参数接收,不处理业务逻辑 - Service层:核心业务逻辑,参数校验 - Store层:数据储存层,负责数据查询和事务处理(@DSTransactional) - Mapper层:数据库操作 ## 扩展分层 - **Agg(聚合根/Model)层**:领域模型对象,位于 `sales` 模块的 `model` 包下 - 使用 `@Getter` + `@ToString`(不用 `@Data`,通过方法封装属性设置) - 必须提供 `create()` / `modify()` / `fillingDbId()` 方法封装属性设置 - `create` 和 `modify` 共用私有 `fillingMainData()` 方法 - 全参构造函数用于 Entity→Agg 的转换 - **Bond层**:复杂业务编排层,承载核心业务逻辑(几千行级别),命名如 `XxxBond` - 标注 `@Component`,直接注入多个 Mapper/Service/Store - 不遵循标准 CRUD 模板,按业务场景定制方法 - **Trans层**:跨领域业务编排层,命名如 `XxxServiceTrans` - 标注 `@Component`,使用 `@DSTransactional` 保障多数据源事务 - 整合多个 Service/Store 的调用 ## 各层注解规范 | 层 | 类注解 | 注入方式 | 事务注解 | |---|--------|---------|--------| | Controller | `@RestController` + `@Slf4j` + `@Api(tags="...")` | `@Autowired` | 无 | | Service接口 | 无 | - | - | | ServiceImpl | `@Slf4j` + `@Service` | `@Autowired` | 无(事务放Store层) | | Store接口 | 无 | - | - | | StoreImpl | `@Slf4j` + `@Component` | `@Autowired` | `@DSTransactional`(写操作) | | Agg | `@Getter` + `@ToString` + `@ApiModel` | - | - | | Bond | `@Component` | `@Autowired` | 按需 | **关键规则**: - Store层用 `@Component` 而非 `@Service` - 事务使用 `@DSTransactional`(`com.baomidou.dynamic.datasource.annotation.DSTransactional`),而非 `@Transactional` - 特殊场景使用 `@DS("primary")` 或 `@DS("hologres")` 指定数据源 ## 各层包路径归属 | 类型 | 包路径 | 所属模块 | |------|--------|----------| | Entity | `com.lvcc.biz.entity.sales.{module}` | biz | | DTO | `com.lvcc.biz.dto.sales.{module}` | biz | | QueryDTO | `com.lvcc.biz.dto.sales.{module}` | biz | | VO | `com.lvcc.biz.vo.sales.{module}` | biz | | Mapper | `com.lvcc.biz.dao.sales.{module}` | biz | | Mapper XML | `biz/src/main/resources/mapper/{module}/` | biz | | Controller | `com.lvcc.sales.{module}.controller` | sales | | Service | `com.lvcc.sales.{module}.service` | sales | | ServiceImpl | `com.lvcc.sales.{module}.service.impl` | sales | | Agg(Model) | `com.lvcc.sales.{module}.model` | sales | | Store | `com.lvcc.sales.{module}.store` 或 `com.lvcc.biz.store.sales.{module}` | sales/biz | | StoreImpl | `com.lvcc.sales.{module}.store.impl` 或 `com.lvcc.biz.store.sales.{module}.impl` | sales/biz | | Bond | `com.lvcc.sales.{module}.bond` | sales | ## 各层返回值规范 | 层 | 操作类型 | 返回类型 | 示例 | |----|---------|---------|------| | Controller | 所有 | `RestResponse` | `RestResponse.success().setData(data)` | | Service | 分页查询 | `Page<VO>` | `Page<AiOutboundCallVO>` | | Service | 新增/删除/更新 | `boolean` | throws FebsException | | Service | 详情查询 | `VO` | throws FebsException | | Store | 分页查询 | `List<VO>` | Mapper直返 | | Store | 新增或修改 | `Long`(主键ID) | - | | Store | 删除 | `boolean` | - | | Store | 详情 | `Agg` 或 `VO` | - | ## Controller 标准方法模板 ```java // 新增:POST /save @PostMapping("/save") public RestResponse create(@RequestBody XxxDTO dto) throws FebsException // 单删:GET /delete/{id} @GetMapping("/delete/{id}") public RestResponse delete(@PathVariable("id") String id) throws FebsException // 批删:POST /delete/batch @PostMapping("/delete/batch") public RestResponse deleteBatch(@RequestBody String ids) throws FebsException // JSON字符串手动解析 // 分页查询:POST /list @PostMapping("/list") public RestResponse queryXxxPage(@RequestBody XxxQueryDTO queryDto) // 不throws // 详情查询:GET /get/{id} @GetMapping("/get/{id}") public RestResponse findXxxById(@PathVariable("id") String id) throws FebsException // 更新:POST /update/{id} @PostMapping("/update/{id}") public RestResponse update(@PathVariable("id") String id, @RequestBody XxxDTO dto) throws FebsException ``` **关键规则**: - id 参数类型统一为 **String**(Controller层),在Service层转为Long - 批量操作接收 JSON字符串,用 `JSON.parse()` 手动解析 - 更新操作路径为 `/update/{id}`,将 id 设置到 dto:`dto.setId(Long.valueOf(id))` - 分页查询方法 **不throws FebsException** - 返回格式:`RestResponse.success().setData(data)` 或 `RestResponse.success("成功")` ## 分页查询模式 - QueryDTO 继承 `PageBaseDTO`(含 pageNum=1, pageSize=10) - Service层构造 `Page<VO>` 对象:`new Page<>(pageNum, pageSize)` - Store层方法签名:`List<VO> queryXxxPage(Page<VO> queryPage, XxxQueryDTO queryDto)` - Mapper方法签名:`List<VO> queryXxxRecord(Page<VO> queryPage, @Param("data") XxxQueryDTO queryDto)` - MyBatis-Plus 自动将分页信息填充到 Page 对象 ## DDD设计原则 - 领域模型优先,数据库仅为持久化细节 - 通过聚合根(Agg)维护数据一致性 - 通过限界上下文将系统拆分为高内聚、低耦合的模块 - Agg不使用 `@Setter` / `@Data` 注解(通过 `create`/`modify`/`fillingDbId` 方法保证不可变性) - 添加字段需同步改动:Entity → StoreImpl → ServiceImpl → Agg → VO/DTO(按需) ## Store层保存模式 ```java @DSTransactional public Long saveXxxRecord(XxxAgg saveEntity, String userKey) { XxxEntity curEntity = this.findXxxEntityByDataKey(saveEntity.getId()); // 1. 查询现有实体 curEntity = this.buildXxxEntity(curEntity, saveEntity, userKey); // 2. 构建实体 if (ObjectUtil.isEmpty(curEntity.getId())) { xxxMapper.insert(curEntity); // 3. id为空 → insert } else { xxxMapper.updateById(curEntity); // 4. id有值 → updateById } saveEntity.fillingDbId(curEntity.getId()); // 5. 回填聚合根的id return curEntity.getId(); // 6. 返回主键 } ``` - `buildXxxEntity` 方法处理新增/修改场景的Entity构建 - 逻辑删除:`set(XxxEntity::getDeleted, 1)` 而非物理删除 - 查询实体时必须加 `eq(XxxEntity::getDeleted, 0)` 条件 ## 获取当前用户 - Service层:`UserInfo user = JWTUtil.getCurrentUser(); String userKey = String.valueOf(user.getUserId());` - Controller层日志:`FebsUtil.getCurrentUser()` ## 数据权限注解 ```java @ComplexPermissions(andPermissionEnums = MenuPermEnum.XXX, message = "暂无访问权限") ``` - 用于Controller方法上,控制菜单权限 - 权限码在 `MenuPermEnum` 枚举中定义 ## 操作日志注解 ```java @Log("操作描述") ``` - 用于Controller方法上,记录操作日志 ## 代码生成器 - 新增表必须采用代码生成器生成的代码风格 - 添加字段时需改动位置:Entity → StoreImpl → ServiceImpl → Agg层 → VO和DTO(按需补充) ## 代码分支规范 - 主分支:`master_test`,禁止在未经允许的情况下直接修改并提交代码 - 需求合集:`factory_platform+合集名称`,如 `factory_platform_M20250901` - 线上优化:`master_online_optimization+日期`,如 `master_online_optimization_20251101` - 普通需求:`factory_+需求英文命名+日期`,如 `factory_ai_perms_20250929` - 合并规范:完成需求后进行代码提测,测试完成后由组长根据上线清单进行代码合并 - 提测时必须在提测单标明是否有SQL,并将SQL粘贴到提测单 - 测试开始时需重新合并 `master_production` 到自己的提测分支 ## 本地开发环境 - 本地开发禁止连接测试环境的消息队列 - 微服务版本禁止注册测试环境的注册中心 - 启动顺序:Nacos → Gateway → Sales → 其他按需启动 - 外网映射在dev环境 `t_service_config` 表中配置,地址格式 `http://factorytransmit.frp.lbbtech.com/服务标识/接口路径`

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询