Files
simple-template/docs/backend-feature-development.md
T
2026-05-12 14:07:54 +08:00

156 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 后端业务功能开发规范
本文是本项目后端新增或修改业务功能时的权威规范。开发后台管理端业务模块时,必须优先遵循本项目现有架构,而不是套用通用 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。
- 权限、日志、异常、测试和现有项目风格一致。