# 后端业务功能开发规范 本文是本项目后端新增或修改业务功能时的权威规范。开发后台管理端业务模块时,必须优先遵循本项目现有架构,而不是套用通用 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// └── XxxController.java ``` 业务代码放在 `agileboot-domain`: ```text backend/agileboot-domain/src/main/java/com/agileboot/domain//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`,放到现有领域下;如果是独立业务领域,创建新的 `` 包名,例如 `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`。 Model 承载业务规则: - 从 `AddXxxCommand`、`UpdateXxxCommand` 加载字段。 - 封装唯一性校验、状态校验、是否允许删除、业务状态流转等规则。 - 需要数据库判断时,通过构造注入的 `XxxService` 查询。 - 业务失败时抛出 `ApiException`,不要返回布尔值让上层解释。 ModelFactory 负责创建和加载模型: - `create()` 返回带有依赖的空模型。 - `loadById(id)` 从数据库加载 Entity,并包装为 Model。 - 如果未找到必要数据,按项目现有异常风格处理。 db 包只负责持久化: - `XxxEntity` 映射数据库表。 - `XxxDO` 承载复杂查询结果,例如关联表字段、统计字段、报表字段。 - `XxxMapper` 继承 MyBatis Plus `BaseMapper`。 - `XxxService` 继承 `IService`,声明复用型查询方法。 - `XxxServiceImpl` 继承 `ServiceImpl`,实现唯一性检查、关联检查、复杂查询等。 - 复杂 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`。 ## 开发流程 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`。 - 写请求使用 Command。 - 复杂查询结果对象使用 DO,并在 ApplicationService 转换为 DTO。 - 权限、日志、异常、测试和现有项目风格一致。