|
|
@@ -0,0 +1,155 @@
|
|
|
+# 后端业务功能开发规范
|
|
|
+
|
|
|
+本文是本项目后端新增或修改业务功能时的权威规范。开发后台管理端业务模块时,必须优先遵循本项目现有架构,而不是套用通用 Spring Boot 三层模板。
|
|
|
+
|
|
|
+## 架构原则
|
|
|
+
|
|
|
+后端业务代码按 `Controller -> ApplicationService -> Model -> db Service/Mapper` 组织。
|
|
|
+
|
|
|
+优先参考这些现有模块:
|
|
|
+
|
|
|
+- `backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post`
|
|
|
+- `backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user`
|
|
|
+- `backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role`
|
|
|
+- `backend/agileboot-domain/src/main/java/com/agileboot/domain/system/notice`
|
|
|
+- `backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system`
|
|
|
+
|
|
|
+不要让 Controller 直接调用 Mapper,不要把业务规则写在 Controller,也不要直接把 Entity 或 DO 返回给前端。
|
|
|
+
|
|
|
+## 开发准备
|
|
|
+
|
|
|
+开发新后端业务功能前,应先确认需求所属领域、涉及的数据表、接口范围、权限标识和相似模块。本文是后端业务功能开发的统一规范。
|
|
|
+
|
|
|
+开始编码前必须先做一次相似模块调研,确认目标功能最接近 `post`、`user`、`role`、`notice` 还是其他模块,再按相似模块的命名、包路径、注解、分页、异常、权限、日志和测试风格实现。
|
|
|
+
|
|
|
+## 目录结构
|
|
|
+
|
|
|
+后台管理端入口放在 `agileboot-admin`:
|
|
|
+
|
|
|
+```text
|
|
|
+backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/<area>/
|
|
|
+└── XxxController.java
|
|
|
+```
|
|
|
+
|
|
|
+业务代码放在 `agileboot-domain`:
|
|
|
+
|
|
|
+```text
|
|
|
+backend/agileboot-domain/src/main/java/com/agileboot/domain/<area>/xxx/
|
|
|
+├── XxxApplicationService.java
|
|
|
+├── command/
|
|
|
+│ ├── AddXxxCommand.java
|
|
|
+│ └── UpdateXxxCommand.java
|
|
|
+├── query/
|
|
|
+│ └── XxxQuery.java
|
|
|
+├── dto/
|
|
|
+│ ├── XxxDTO.java
|
|
|
+│ └── XxxDetailDTO.java
|
|
|
+├── model/
|
|
|
+│ ├── XxxModel.java
|
|
|
+│ └── XxxModelFactory.java
|
|
|
+└── db/
|
|
|
+ ├── XxxEntity.java
|
|
|
+ ├── XxxDO.java
|
|
|
+ ├── XxxMapper.java
|
|
|
+ ├── XxxService.java
|
|
|
+ └── XxxServiceImpl.java
|
|
|
+```
|
|
|
+
|
|
|
+`XxxDO` 是可选文件。只有当查询结果包含 join、聚合、报表字段或其他不完全匹配 Entity 的字段时才创建。
|
|
|
+
|
|
|
+如果业务属于已有领域,例如 `system`,放到现有领域下;如果是独立业务领域,创建新的 `<area>` 包名,例如 `business`。
|
|
|
+
|
|
|
+## 各层职责
|
|
|
+
|
|
|
+Controller 只负责 HTTP 层:
|
|
|
+
|
|
|
+- 声明 `@RestController`、`@RequestMapping`、`@Validated`、Swagger 注解。
|
|
|
+- 接收 `Command`、`Query`、路径参数和请求参数。
|
|
|
+- 使用 `@PreAuthorize("@permission.has('xxx:yyy:zzz')")` 做权限控制。
|
|
|
+- 对新增、修改、删除、导出等操作使用 `@AccessLog`。
|
|
|
+- 调用 `XxxApplicationService`。
|
|
|
+- 使用 `ResponseDTO.ok(...)` 返回结果。
|
|
|
+
|
|
|
+ApplicationService 负责编排业务用例:
|
|
|
+
|
|
|
+- 分页查询、详情查询、导出查询、新增、修改、删除。
|
|
|
+- 创建或加载 `XxxModel`。
|
|
|
+- 调用领域模型完成业务校验和状态变化。
|
|
|
+- 调用 `db` 包中的 Service 完成查询和持久化。
|
|
|
+- 将 Entity 或 DO 转换为 DTO。
|
|
|
+- 分页结果使用 `PageDTO<T>`。
|
|
|
+
|
|
|
+Model 承载业务规则:
|
|
|
+
|
|
|
+- 从 `AddXxxCommand`、`UpdateXxxCommand` 加载字段。
|
|
|
+- 封装唯一性校验、状态校验、是否允许删除、业务状态流转等规则。
|
|
|
+- 需要数据库判断时,通过构造注入的 `XxxService` 查询。
|
|
|
+- 业务失败时抛出 `ApiException`,不要返回布尔值让上层解释。
|
|
|
+
|
|
|
+ModelFactory 负责创建和加载模型:
|
|
|
+
|
|
|
+- `create()` 返回带有依赖的空模型。
|
|
|
+- `loadById(id)` 从数据库加载 Entity,并包装为 Model。
|
|
|
+- 如果未找到必要数据,按项目现有异常风格处理。
|
|
|
+
|
|
|
+db 包只负责持久化:
|
|
|
+
|
|
|
+- `XxxEntity` 映射数据库表。
|
|
|
+- `XxxDO` 承载复杂查询结果,例如关联表字段、统计字段、报表字段。
|
|
|
+- `XxxMapper` 继承 MyBatis Plus `BaseMapper<XxxEntity>`。
|
|
|
+- `XxxService` 继承 `IService<XxxEntity>`,声明复用型查询方法。
|
|
|
+- `XxxServiceImpl` 继承 `ServiceImpl<XxxMapper, XxxEntity>`,实现唯一性检查、关联检查、复杂查询等。
|
|
|
+- 复杂 SQL 放到 mapper XML,简单条件优先使用 MyBatis Plus wrapper。
|
|
|
+
|
|
|
+`XxxDO` 属于数据库查询结果对象,不是前端响应对象,也不是请求对象。Mapper 或 Service 可以返回 `XxxDO`,但 ApplicationService 必须转换为 `XxxDTO` 后再交给 Controller 返回。
|
|
|
+
|
|
|
+Command、Query、DTO 的边界:
|
|
|
+
|
|
|
+- `Command` 用于新增、修改等写请求,不要直接接收 Entity。
|
|
|
+- `Query` 用于列表、搜索、分页条件,并提供 `toPage()`、`toQueryWrapper()` 等项目已有风格的方法。
|
|
|
+- `DTO` 用于响应前端,不要直接暴露 Entity 或 DO。
|
|
|
+- 批量删除优先使用 `BulkOperationCommand<Long>`。
|
|
|
+
|
|
|
+## 开发流程
|
|
|
+
|
|
|
+1. 检索并阅读一个最相似的现有模块,确认命名、包路径、注解、分页、异常、测试风格。
|
|
|
+2. 确认数据库表结构,保持主键、软删除、审计字段、字段命名与现有表一致。
|
|
|
+3. 创建 `db` 包:`Entity`、`Mapper`、`Service`、`ServiceImpl`;如查询结果包含关联表字段、统计字段或报表字段,再增加 `XxxDO`。
|
|
|
+4. 创建 API 契约:`AddXxxCommand`、`UpdateXxxCommand`、`XxxQuery`、`XxxDTO`,需要详情时添加 `XxxDetailDTO`。
|
|
|
+5. 创建 `XxxModel` 和 `XxxModelFactory`,把业务校验放进 Model。
|
|
|
+6. 创建 `XxxApplicationService`,编排查询、新增、修改、删除、导出等用例。
|
|
|
+7. 创建 `XxxController`,加路由、权限、操作日志和统一响应。
|
|
|
+8. 如功能出现在后台菜单,补充权限标识、菜单 SQL 或清楚说明需要配置的权限码。
|
|
|
+9. 增加聚焦测试,至少覆盖核心业务校验和主要用例。
|
|
|
+10. 运行相关 Maven 测试或编译检查;如果不能运行,说明原因。
|
|
|
+
|
|
|
+开发过程中如果发现本文未覆盖的模式,优先参考现有模块,而不是引入新的架构风格。确实需要新增模式时,应先更新本文,再按新规范实现。
|
|
|
+
|
|
|
+## 权限、日志和错误
|
|
|
+
|
|
|
+权限码必须和前端菜单或按钮权限保持一致,格式参考现有系统功能:
|
|
|
+
|
|
|
+```java
|
|
|
+@PreAuthorize("@permission.has('system:post:add')")
|
|
|
+```
|
|
|
+
|
|
|
+操作日志按业务动作选择类型:
|
|
|
+
|
|
|
+```java
|
|
|
+@AccessLog(title = "业务名称", businessType = BusinessTypeEnum.ADD)
|
|
|
+@AccessLog(title = "业务名称", businessType = BusinessTypeEnum.MODIFY)
|
|
|
+@AccessLog(title = "业务名称", businessType = BusinessTypeEnum.DELETE)
|
|
|
+@AccessLog(title = "业务名称", businessType = BusinessTypeEnum.EXPORT)
|
|
|
+```
|
|
|
+
|
|
|
+业务错误使用 `ApiException` 和 `ErrorCode.Business`。新增业务错误时,按现有错误码结构补充枚举或常量,不要在 Controller 中拼接错误响应。
|
|
|
+
|
|
|
+## 验收清单
|
|
|
+
|
|
|
+- 新代码目录结构与相似模块一致。
|
|
|
+- Controller 只有 HTTP 编排逻辑。
|
|
|
+- 业务校验位于 Model 或 ApplicationService,不散落在前端或 Controller。
|
|
|
+- 查询返回 DTO,分页返回 `PageDTO<T>`。
|
|
|
+- 写请求使用 Command。
|
|
|
+- 复杂查询结果对象使用 DO,并在 ApplicationService 转换为 DTO。
|
|
|
+- 权限、日志、异常、测试和现有项目风格一致。
|