218 lines
7.8 KiB
Markdown
218 lines
7.8 KiB
Markdown
# 02 — 后端规则
|
||
|
||
> **适用**:所有后端 AI 开发任务。
|
||
|
||
---
|
||
|
||
## 分层不变式
|
||
|
||
```
|
||
Controller → 参数校验 + 调 Service + 返回统一格式
|
||
禁止:写业务逻辑、直接调 Mapper、处理事务
|
||
|
||
Service → 业务逻辑 + 事务管理
|
||
禁止:处理 HTTP 请求/响应、直接操作 Request/Response
|
||
|
||
Mapper → 数据访问(MyBatis-Plus BaseMapper)
|
||
禁止:写业务逻辑、调用其他 Mapper
|
||
|
||
Entity → 数据映射(@TableName 对应表名)
|
||
禁止:写业务方法、放非持久化字段(放 DTO/VO)
|
||
```
|
||
|
||
### 包结构
|
||
|
||
```
|
||
com.ghb.base/
|
||
├── system/ # 系统模块(不改)
|
||
│ ├── entity/ SysUser, SysRole, SysMenu...
|
||
│ ├── controller/
|
||
│ └── service/
|
||
└── business/ # 业务模块 ← 你的代码放这里
|
||
├── entity/ # 继承 JeecgBoot 的 BaseEntity
|
||
├── controller/ # 继承 JeecgController
|
||
├── service/ # impl/ 继承 ServiceImpl
|
||
├── mapper/ # 继承 BaseMapper
|
||
│ └── xml/ # MyBatis XML(复杂查询才需要)
|
||
└── vo/ # 请求/响应 DTO (*VO, *Request, *ImportRow)
|
||
```
|
||
|
||
---
|
||
|
||
## 命名规则
|
||
|
||
| 元素 | 规则 | 示例(正确 → 错误) |
|
||
|------|------|---------------------|
|
||
| **类名** | 大驼峰,名词 | `TaskController` `OrderService` `UserMapper` |
|
||
| **方法名** | 小驼峰,动词开头 | `getById()` `saveTask()` `listByStatus()` |
|
||
| **变量** | 小驼峰,有意义 | `taskList` `userId` → ❌ `list` `id` `data` |
|
||
| **包名** | 全小写,点分隔 | `com.xxx.server.controller` |
|
||
| **Entity** | 大驼峰,对应表名 | 表 `task_apply` → 类 `TaskApply` |
|
||
| **DTO** | 大驼峰,后缀 DTO/VO/Request | `TaskCreateRequest` `UserListVO` |
|
||
| **常量** | 全大写,下划线分隔 | `MAX_RETRY_COUNT` `DEFAULT_PAGE_SIZE` |
|
||
| **SQL 表名** | 小写,下划线分隔 | `task_apply` `user_profile` |
|
||
| **SQL 字段** | 小写,下划线分隔 | `create_time` `task_id` `del_flag` |
|
||
| **URL 路径** | 小写,短横线或斜杠 | `/app/task/list` → ❌ `/app/Task/GetList` |
|
||
| **配置文件** | kebab-case 或小写 | `application-prod.yml` |
|
||
|
||
### 长度控制
|
||
|
||
类名、方法名、表名不要过长。超过 3 个单词或 30 个字符时,用通用缩写。
|
||
|
||
**前缀也要缩**:模块前缀用一个单词,别堆多个词。
|
||
|
||
| 完整 | 缩写 | JeecgBoot 实际案例 |
|
||
|------|------|-------------------|
|
||
| Department | Dept | `SysDepartRolePermission` → `SysDeptRolePerm` |
|
||
| Permission | Perm | 同上 |
|
||
| Announcement | Notice | `SysAnnouncementSend` → `SysNoticeSend` |
|
||
| Enterprise | Ent | `WechatEnterprise` → `WxEnt` |
|
||
| Message | Msg | `SysMessageTemplate` → `SysMsgTemplate` |
|
||
|
||
```java
|
||
// ❌ JeecgBoot 原版 — 太长
|
||
SysDepartRolePermissionServiceImpl // 35 字符
|
||
SysAnnouncementSendServiceImpl // 30 字符
|
||
ThirdAppWechatEnterpriseServiceImpl // 35 字符
|
||
|
||
// ✅ 缩写后
|
||
SysDeptRolePermServiceImpl // 26 字符
|
||
SysNoticeSendServiceImpl // 25 字符
|
||
ThirdAppWxEntServiceImpl // 27 字符
|
||
```
|
||
|
||
**原则**:优先用全称,超长再缩写。缩写必须一眼能认出含义,不自造别人看不懂的缩写。
|
||
|
||
---
|
||
|
||
## 注释规则
|
||
|
||
| 位置 | 要求 | 示例 |
|
||
|------|------|------|
|
||
| **类/接口** | 必须有 Javadoc,说明职责 | `/** 任务管理 Controller,处理任务的增删改查 */` |
|
||
| **公共方法** | 必须有 Javadoc,说明入参/返回/异常 | `/** @param taskId 任务ID @return 任务详情 @throws 无 */` |
|
||
| **复杂逻辑** | 行内注释说明"为什么这么做" | `// 先查缓存再查库,避免击穿` |
|
||
| **常量** | 必须有注释说明含义 | `/** 最大重试次数 */` |
|
||
| **TODO/FIXME** | 必须有负责人和日期 | `// TODO(yaoshuli 2026-06) 后续改为配置项` |
|
||
| **禁止** | ❌ 注释写"做了什么"(代码本身已说明) | `// 查询任务列表` ← 删掉 |
|
||
| **禁止** | ❌ 注释掉的旧代码 | 直接删,Git 有历史 |
|
||
| **禁止** | ❌ 无意义注释 | `// 定义一个变量` `// 返回结果` |
|
||
| **禁止** | ❌ Controller 方法加 Javadoc 说"这是xxx接口" | 写业务含义,不写技术废话 |
|
||
|
||
### 注释示例
|
||
|
||
```java
|
||
/** 任务服务,负责任务的创建、分配、状态流转 */
|
||
@Service
|
||
public class TaskServiceImpl implements TaskService {
|
||
|
||
/** 单次批量操作上限 */
|
||
private static final int BATCH_LIMIT = 100;
|
||
|
||
/**
|
||
* 根据状态和截止时间查询待处理任务。
|
||
* 先查 Redis 缓存,未命中再查 MySQL。
|
||
*
|
||
* @param status 任务状态,不能为 null
|
||
* @param deadline 截止时间,只查此时间之前的任务
|
||
* @return 任务列表,可能为空
|
||
*/
|
||
@Override
|
||
public List<Task> listPending(String status, LocalDateTime deadline) {
|
||
// 缓存 key: pending:{status}
|
||
String cacheKey = "pending:" + status;
|
||
List<Task> cached = cacheService.get(cacheKey);
|
||
if (cached != null) return cached;
|
||
|
||
// 查库(这里用复合索引 idx_status_deadline)
|
||
List<Task> tasks = taskMapper.selectByStatusBefore(status, deadline);
|
||
cacheService.set(cacheKey, tasks, 300);
|
||
return tasks;
|
||
}
|
||
}
|
||
```
|
||
|
||
## 新增功能标准步骤
|
||
|
||
```
|
||
1. 建表 SQL → [项目数据库脚本目录]
|
||
2. Entity → 表映射
|
||
3. Mapper → 继承 BaseMapper
|
||
4. Service 接口+实现 → 业务逻辑
|
||
5. Controller → 接口暴露
|
||
6. 编译验证 → 构建通过
|
||
```
|
||
|
||
---
|
||
|
||
## CRUD 模板(填空式)
|
||
|
||
```java
|
||
// ===== 分页列表 =====
|
||
@GetMapping("/list")
|
||
public Result<IPage<Xxx>> list(@RequestParam(defaultValue = "1") int page,
|
||
@RequestParam(defaultValue = "10") int size) {
|
||
Page<Xxx> p = new Page<>(page, size);
|
||
// [填空] 构建查询条件
|
||
return Result.ok(service.page(p, wrapper));
|
||
}
|
||
|
||
// ===== 详情 =====
|
||
@GetMapping("/{id}")
|
||
public Result<Xxx> detail(@PathVariable Long id) {
|
||
Xxx entity = service.getById(id);
|
||
if (entity == null) return Result.error("[资源]不存在");
|
||
return Result.ok(entity);
|
||
}
|
||
|
||
// ===== 新增 =====
|
||
@PostMapping
|
||
public Result<?> create(@RequestBody @Valid XxxDto dto) {
|
||
// [填空] DTO → Entity 转换
|
||
service.save(entity);
|
||
return Result.ok();
|
||
}
|
||
|
||
// ===== 更新 =====
|
||
@PutMapping("/{id}")
|
||
public Result<?> update(@PathVariable Long id, @RequestBody @Valid XxxDto dto) {
|
||
Xxx entity = service.getById(id);
|
||
if (entity == null) return Result.error("[资源]不存在");
|
||
// [填空] 字段更新
|
||
service.updateById(entity);
|
||
return Result.ok();
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 禁止清单
|
||
|
||
| 类别 | ❌ 禁止 |
|
||
|------|--------|
|
||
| **分层** | Controller 里写 if/else 业务判断 |
|
||
| **分层** | Controller 直接调 Mapper/Repository |
|
||
| **分层** | Entity 里写业务方法 |
|
||
| **数据** | SQL/查询条件字符串拼接 |
|
||
| **数据** | 查不到不判空,直接返回可能 NPE |
|
||
| **数据** | `selectOne` / `getOne` 不做唯一性约束 |
|
||
| **输入** | 入参不校验(该用 `@Valid` 的地方手撸 if) |
|
||
| **输出** | 返回裸对象、裸字符串、自造格式 |
|
||
| **值** | 代码里硬编码魔法数字、魔法字符串 |
|
||
| **事务** | 该加事务的地方漏加 |
|
||
|
||
---
|
||
|
||
## 检查表
|
||
|
||
每完成一个后端任务,逐项自检:
|
||
|
||
- [ ] 编译通过(`mvn compile` / `go build` / 对应构建命令)
|
||
- [ ] 所有返回值是统一格式,无裸返回
|
||
- [ ] 分页接口格式正确(`list/total/pages/current/size`)
|
||
- [ ] Controller 方法体不超过 20 行(超过说明写了业务逻辑)
|
||
- [ ] 查不到/null 路径有明确的 `fail` 返回
|
||
- [ ] 改了接口 → 已 grep 同步所有前端调用方
|
||
- [ ] 新增/改字段 → 已更新数据库脚本
|
||
- [ ] 无禁止清单中的违规项
|