@llryiop/avatar-boot-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +309 -0
- package/bin/cli.js +3 -0
- package/docs/plans/2026-03-12-avatar-boot-cli-design.md +73 -0
- package/docs/plans/2026-03-12-avatar-boot-cli-plan.md +681 -0
- package/package.json +28 -0
- package/src/index.js +78 -0
- package/src/prompts.js +78 -0
- package/src/template.js +37 -0
- package/src/transform.js +172 -0
- package/src/utils.js +34 -0
- package/templates/.claude/rules/architecture-redlines.md +146 -0
- package/templates/.claude/rules/code-review-standards.md +137 -0
- package/templates/.claude/rules/coding-standards.md +56 -0
- package/templates/.claude/rules/git-commit.md +59 -0
- package/templates/.claude/rules/layered-architecture.md +201 -0
- package/templates/.claude/rules/mybatis-plus.md +263 -0
- package/templates/.claude/rules/tech-stack.md +41 -0
- package/templates/.claude/rules/version.md +467 -0
- package/templates/.claude/settings.local.json +18 -0
- package/templates/.claude/skills/ai-tool-guide/SKILL.md +314 -0
- package/templates/.claude/skills/api-design/SKILL.md +200 -0
- package/templates/.claude/skills/api-doc-generator/SKILL.md +380 -0
- package/templates/.claude/skills/api-service-module-creator/SKILL.md +1114 -0
- package/templates/.claude/skills/avatar-boot-starter-feign/SKILL.md +243 -0
- package/templates/.claude/skills/avatar-boot-starter-job/SKILL.md +437 -0
- package/templates/.claude/skills/avatar-boot-starter-kafka/SKILL.md +580 -0
- package/templates/.claude/skills/avatar-boot-starter-mysql/SKILL.md +572 -0
- package/templates/.claude/skills/avatar-boot-starter-nacos/SKILL.md +901 -0
- package/templates/.claude/skills/avatar-boot-starter-oss/SKILL.md +594 -0
- package/templates/.claude/skills/avatar-boot-starter-redis/SKILL.md +586 -0
- package/templates/.claude/skills/avatar-boot-starter-rocketmq/SKILL.md +662 -0
- package/templates/.claude/skills/avatar-boot-starter-web/SKILL.md +1007 -0
- package/templates/.claude/skills/changelog-generator/SKILL.md +114 -0
- package/templates/.claude/skills/code-review/SKILL.md +239 -0
- package/templates/.claude/skills/crud-generator/SKILL.md +824 -0
- package/templates/.claude/skills/database-design/SKILL.md +377 -0
- package/templates/.claude/skills/deployment-config/SKILL.md +277 -0
- package/templates/.claude/skills/incident-analysis/SKILL.md +241 -0
- package/templates/.claude/skills/integration-test-generator/SKILL.md +496 -0
- package/templates/.claude/skills/prompt-engineering/SKILL.md +249 -0
- package/templates/.claude/skills/requirement-management/SKILL.md +244 -0
- package/templates/.claude/skills/security-audit/SKILL.md +330 -0
- package/templates/.claude/skills/test-case-design/SKILL.md +257 -0
- package/templates/.claude/skills/testing-workflow/SKILL.md +68 -0
- package/templates/.claude/skills/troubleshooting/SKILL.md +240 -0
- package/templates/CLAUDE.md +173 -0
- package/templates/README.md +303 -0
- package/templates/avatar-scaffold-api/pom.xml +41 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/api/LoginFeignClient.java +40 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/constant/LoginConstant.java +21 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/dto/request/LoginRequest.java +17 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/dto/request/RefreshTokenRequest.java +14 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/dto/response/LoginResponse.java +31 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/dto/response/TokenInfoResponse.java +25 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/enums/LoginTypeEnum.java +23 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/exception/LoginException.java +23 -0
- package/templates/avatar-scaffold-service/k8s-app/Dockerfile +14 -0
- package/templates/avatar-scaffold-service/k8s-app/Dockerfile-arm64 +14 -0
- package/templates/avatar-scaffold-service/packaging/assembly.xml +16 -0
- package/templates/avatar-scaffold-service/pom.xml +150 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/Application.java +21 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/config/LoginConfig.java +20 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/controller/LoginController.java +37 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/converter/LoginConverter.java +54 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/feign/DemoFeign.java +21 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/repository/entity/UserLoginEntity.java +33 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/repository/entity/UserTokenEntity.java +39 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/repository/mapper/UserLoginMapper.java +20 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/service/LoginService.java +22 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/service/impl/LoginServiceImpl.java +43 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/utils/LoginUtils.java +31 -0
- package/templates/avatar-scaffold-service/src/main/resources/application-dev.yaml +29 -0
- package/templates/avatar-scaffold-service/src/main/resources/application-local.yaml +61 -0
- package/templates/avatar-scaffold-service/src/main/resources/application-prod.yaml +28 -0
- package/templates/avatar-scaffold-service/src/main/resources/application-test.yaml +28 -0
- package/templates/avatar-scaffold-service/src/main/resources/application.yaml +12 -0
- package/templates/pom.xml +98 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# 编码规范
|
|
2
|
+
|
|
3
|
+
> 规则类型: 🔴 强制执行
|
|
4
|
+
> 更新频率: 中(团队规范调整时更新)
|
|
5
|
+
> 相关规则: [architecture-redlines.md](architecture-redlines.md) | [git-commit.md](git-commit.md) | [version.md](version.md)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Java 代码规范
|
|
10
|
+
|
|
11
|
+
### 命名规范
|
|
12
|
+
|
|
13
|
+
- 类名: PascalCase(如 `UserController`)
|
|
14
|
+
- 方法名: camelCase(如 `getUserById`)
|
|
15
|
+
- 常量: UPPER_SNAKE_CASE(如 `MAX_RETRY_COUNT`)
|
|
16
|
+
- 包名: 全小写,使用点分隔(如 `com.iflytek.avatar.login`)
|
|
17
|
+
|
|
18
|
+
### 代码长度限制
|
|
19
|
+
|
|
20
|
+
- 方法长度不超过 50 行
|
|
21
|
+
- 类文件长度不超过 500 行,超过需拆分
|
|
22
|
+
- 单行代码长度不超过 120 字符
|
|
23
|
+
|
|
24
|
+
### 注释规范
|
|
25
|
+
|
|
26
|
+
- 公共 API 必须有 Javadoc 注释
|
|
27
|
+
- 复杂业务逻辑必须有行内注释
|
|
28
|
+
- 禁止无意义的注释(如 `// 获取用户` 在 `getUser()` 方法上)
|
|
29
|
+
|
|
30
|
+
### 异常处理
|
|
31
|
+
|
|
32
|
+
- 使用 `@RestControllerAdvice` 统一处理异常
|
|
33
|
+
- 业务异常继承自自定义 `BusinessException`
|
|
34
|
+
- 禁止捕获异常后不处理(空 catch 块)
|
|
35
|
+
|
|
36
|
+
### 日志规范
|
|
37
|
+
|
|
38
|
+
- 使用 SLF4J + Logback
|
|
39
|
+
- 日志级别: ERROR(错误)、WARN(警告)、INFO(关键信息)、DEBUG(调试信息)
|
|
40
|
+
- 禁止使用 `System.out.println()`
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Maven 配置规范
|
|
45
|
+
|
|
46
|
+
> **完整规则详见**: [version.md](version.md)
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 提交前检查
|
|
51
|
+
|
|
52
|
+
- [ ] 是否编写了单元测试
|
|
53
|
+
- [ ] 测试覆盖率是否达标
|
|
54
|
+
- [ ] 是否所有测试都通过
|
|
55
|
+
- [ ] 是否有 `System.out.println()`
|
|
56
|
+
- [ ] 是否有注释掉的大段代码
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Git 提交规范
|
|
2
|
+
|
|
3
|
+
> 规则类型: 🔴 强制执行
|
|
4
|
+
> 更新频率: 低
|
|
5
|
+
> 相关规则: [coding-standards.md](coding-standards.md)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Commit Message 格式
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
<type>(<scope>): <subject>
|
|
13
|
+
|
|
14
|
+
<body>
|
|
15
|
+
|
|
16
|
+
<footer>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Type 类型
|
|
20
|
+
|
|
21
|
+
| Type | 说明 |
|
|
22
|
+
|------|------|
|
|
23
|
+
| `feat` | 新功能 |
|
|
24
|
+
| `fix` | 修复 bug |
|
|
25
|
+
| `refactor` | 重构(不改变功能) |
|
|
26
|
+
| `perf` | 性能优化 |
|
|
27
|
+
| `style` | 代码格式调整(不影响逻辑) |
|
|
28
|
+
| `test` | 测试相关 |
|
|
29
|
+
| `docs` | 文档更新 |
|
|
30
|
+
| `chore` | 构建/工具/依赖更新 |
|
|
31
|
+
| `revert` | 回滚提交 |
|
|
32
|
+
|
|
33
|
+
## 示例
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
feat(login): 添加手机号登录功能
|
|
37
|
+
|
|
38
|
+
- 新增手机号验证码发送接口
|
|
39
|
+
- 新增手机号登录接口
|
|
40
|
+
- 集成短信服务
|
|
41
|
+
|
|
42
|
+
Closes #123
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
fix(user): 修复用户信息更新失败的问题
|
|
47
|
+
|
|
48
|
+
用户更新时未正确处理空值字段,导致更新失败
|
|
49
|
+
|
|
50
|
+
Fixes #456
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 提交规则
|
|
54
|
+
|
|
55
|
+
- 每次提交必须附带有意义的描述
|
|
56
|
+
- 一次提交只做一件事
|
|
57
|
+
- 提交前必须通过本地测试
|
|
58
|
+
- 禁止提交包含 `System.out.println()` 的代码
|
|
59
|
+
- 禁止提交注释掉的大段代码
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Spring Boot 分层架构规范
|
|
2
|
+
|
|
3
|
+
> 规则类型: 🔴 强制执行
|
|
4
|
+
> 更新频率: 低(架构调整时更新)
|
|
5
|
+
> 相关规则: [architecture-redlines.md](architecture-redlines.md) | [coding-standards.md](coding-standards.md)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Controller 层职责
|
|
10
|
+
|
|
11
|
+
Controller 层**仅负责**参数校验和 Result 封装,禁止包含业务逻辑。
|
|
12
|
+
|
|
13
|
+
### ✅ 正确示例
|
|
14
|
+
|
|
15
|
+
```java
|
|
16
|
+
@RestController
|
|
17
|
+
@RequestMapping("/api/user")
|
|
18
|
+
@RequiredArgsConstructor
|
|
19
|
+
public class UserController {
|
|
20
|
+
|
|
21
|
+
private final UserService userService;
|
|
22
|
+
|
|
23
|
+
@GetMapping("/{id}")
|
|
24
|
+
public Result<UserResponse> getById(@PathVariable Long id) {
|
|
25
|
+
return Result.success(userService.getById(id));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@PostMapping
|
|
29
|
+
public Result<Void> create(@RequestBody @Validated UserCreateRequest request) {
|
|
30
|
+
userService.create(request);
|
|
31
|
+
return Result.success();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@PutMapping("/{id}")
|
|
35
|
+
public Result<Void> update(@PathVariable Long id,
|
|
36
|
+
@RequestBody @Validated UserUpdateRequest request) {
|
|
37
|
+
userService.update(id, request);
|
|
38
|
+
return Result.success();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@DeleteMapping("/{id}")
|
|
42
|
+
public Result<Void> delete(@PathVariable Long id) {
|
|
43
|
+
userService.delete(id);
|
|
44
|
+
return Result.success();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@GetMapping("/page")
|
|
48
|
+
public Result<IPage<UserResponse>> page(UserPageRequest request) {
|
|
49
|
+
return Result.success(userService.page(request));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### ❌ 错误示例
|
|
55
|
+
|
|
56
|
+
```java
|
|
57
|
+
@RestController
|
|
58
|
+
public class UserController {
|
|
59
|
+
|
|
60
|
+
@Autowired
|
|
61
|
+
private UserMapper userMapper; // ❌ Controller 直接依赖 Mapper
|
|
62
|
+
|
|
63
|
+
@GetMapping("/api/user/{id}")
|
|
64
|
+
public UserEntity getById(@PathVariable Long id) { // ❌ 直接返回 Entity,未用 Result<T>
|
|
65
|
+
UserEntity user = userMapper.selectById(id); // ❌ Controller 包含数据访问逻辑
|
|
66
|
+
if (user == null) {
|
|
67
|
+
throw new RuntimeException("用户不存在"); // ❌ 应使用 BusinessException
|
|
68
|
+
}
|
|
69
|
+
return user;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Service 层职责
|
|
77
|
+
|
|
78
|
+
Service 层负责**业务逻辑编排和事务管理**。
|
|
79
|
+
|
|
80
|
+
### 规范要点
|
|
81
|
+
|
|
82
|
+
- Service 接口定义在 `service/` 包下,实现类使用 `Impl` 后缀
|
|
83
|
+
- 事务注解 `@Transactional` 只加在 Service 实现类方法上
|
|
84
|
+
- 写操作必须加 `@Transactional(rollbackFor = Exception.class)`
|
|
85
|
+
- 只读操作加 `@Transactional(readOnly = true)`
|
|
86
|
+
- Service 之间可以互相调用,但禁止循环依赖
|
|
87
|
+
|
|
88
|
+
### ✅ 正确示例
|
|
89
|
+
|
|
90
|
+
```java
|
|
91
|
+
public interface UserService extends IService<UserEntity> {
|
|
92
|
+
UserResponse getById(Long id);
|
|
93
|
+
void create(UserCreateRequest request);
|
|
94
|
+
IPage<UserResponse> page(UserPageRequest request);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@Service
|
|
98
|
+
@RequiredArgsConstructor
|
|
99
|
+
public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity>
|
|
100
|
+
implements UserService {
|
|
101
|
+
|
|
102
|
+
@Override
|
|
103
|
+
@Transactional(readOnly = true)
|
|
104
|
+
public UserResponse getById(Long id) {
|
|
105
|
+
UserEntity entity = getBaseMapper().selectById(id);
|
|
106
|
+
if (entity == null) {
|
|
107
|
+
throw new BusinessException("用户不存在");
|
|
108
|
+
}
|
|
109
|
+
return convertToResponse(entity);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@Override
|
|
113
|
+
@Transactional(rollbackFor = Exception.class)
|
|
114
|
+
public void create(UserCreateRequest request) {
|
|
115
|
+
UserEntity entity = convertToEntity(request);
|
|
116
|
+
save(entity);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### ❌ 错误示例
|
|
122
|
+
|
|
123
|
+
```java
|
|
124
|
+
@Service
|
|
125
|
+
public class UserServiceImpl {
|
|
126
|
+
|
|
127
|
+
@Transactional // ❌ 缺少 rollbackFor,默认只回滚 RuntimeException
|
|
128
|
+
public void create(UserCreateRequest request) {
|
|
129
|
+
// ...
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
public Result<UserResponse> getById(Long id) { // ❌ Service 不应返回 Result,那是 Controller 的职责
|
|
133
|
+
// ...
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Mapper(DAO)层职责
|
|
141
|
+
|
|
142
|
+
Mapper 层负责**纯数据访问**,禁止包含业务逻辑。
|
|
143
|
+
|
|
144
|
+
### 规范要点
|
|
145
|
+
|
|
146
|
+
- Mapper 接口继承 `BaseMapper<T>`,放在 `dao/` 包下
|
|
147
|
+
- 数据库实体类放在 `dao/beans/` 包下
|
|
148
|
+
- 复杂 SQL 使用 XML 映射文件或 `@Select` 等注解
|
|
149
|
+
- 禁止在 Mapper 中编写业务判断逻辑
|
|
150
|
+
|
|
151
|
+
### ✅ 正确示例
|
|
152
|
+
|
|
153
|
+
```java
|
|
154
|
+
@Mapper
|
|
155
|
+
public interface UserMapper extends BaseMapper<UserEntity> {
|
|
156
|
+
|
|
157
|
+
@Select("SELECT * FROM t_user WHERE email = #{email} AND is_deleted = 0")
|
|
158
|
+
UserEntity selectByEmail(@Param("email") String email);
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Entity / DTO / VO 严格区分
|
|
165
|
+
|
|
166
|
+
> 完整的模块包结构详见 [architecture-redlines.md](architecture-redlines.md#目录组织规范)
|
|
167
|
+
|
|
168
|
+
| 类型 | 所在模块 | 包路径 | 用途 |
|
|
169
|
+
|------|---------|--------|------|
|
|
170
|
+
| Entity (DO/PO) | Service 模块 | `dao/beans/` | 数据库表映射,仅在 Mapper 和 Service 层流转 |
|
|
171
|
+
| Request DTO | API 模块 | `entity/request/` | 接收前端/调用方请求参数 |
|
|
172
|
+
| Response DTO | API 模块 | `entity/response/` | 返回给前端/调用方的数据 |
|
|
173
|
+
|
|
174
|
+
### 🔴 跨层依赖规则
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
Controller → Service → Mapper
|
|
178
|
+
↓ ↓ ↓
|
|
179
|
+
Request DTO Entity Entity
|
|
180
|
+
Response DTO Request DTO
|
|
181
|
+
Response DTO
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
- ❌ Controller 禁止直接使用 Entity
|
|
185
|
+
- ❌ Entity 禁止出现在 API 模块中
|
|
186
|
+
- ❌ Mapper 层禁止使用 DTO
|
|
187
|
+
- ✅ Service 层负责 Entity ↔ DTO 的转换
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 分层检查清单
|
|
192
|
+
|
|
193
|
+
- [ ] Controller 是否只做参数校验和 Result 封装
|
|
194
|
+
- [ ] Controller 是否返回 `Result<T>` 类型
|
|
195
|
+
- [ ] Service 写操作是否加了 `@Transactional(rollbackFor = Exception.class)`
|
|
196
|
+
- [ ] Service 只读操作是否加了 `@Transactional(readOnly = true)`
|
|
197
|
+
- [ ] Entity 是否只在 Service 和 Mapper 层使用
|
|
198
|
+
- [ ] DTO 和 Entity 之间是否在 Service 层做了转换
|
|
199
|
+
- [ ] Mapper 是否继承了 `BaseMapper<T>`
|
|
200
|
+
- [ ] 是否存在 Controller 直接调用 Mapper 的情况
|
|
201
|
+
- [ ] 是否存在 Service 返回 `Result<T>` 的情况
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# MyBatis Plus 使用规范
|
|
2
|
+
|
|
3
|
+
> 规则类型: 🔴 强制执行
|
|
4
|
+
> 更新频率: 低(框架升级时更新)
|
|
5
|
+
> 相关规则: [version.md](version.md)(MyBatis Plus 3.5.15)| [layered-architecture.md](layered-architecture.md)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Entity 注解规范
|
|
10
|
+
|
|
11
|
+
### 基础 Entity 模板
|
|
12
|
+
|
|
13
|
+
```java
|
|
14
|
+
@Data
|
|
15
|
+
@TableName("t_user")
|
|
16
|
+
public class UserEntity {
|
|
17
|
+
|
|
18
|
+
@TableId(type = IdType.ASSIGN_ID)
|
|
19
|
+
private Long id;
|
|
20
|
+
|
|
21
|
+
@TableField("username")
|
|
22
|
+
private String username;
|
|
23
|
+
|
|
24
|
+
@TableField("email")
|
|
25
|
+
private String email;
|
|
26
|
+
|
|
27
|
+
@TableField("status")
|
|
28
|
+
private Integer status;
|
|
29
|
+
|
|
30
|
+
@TableField(fill = FieldFill.INSERT)
|
|
31
|
+
private LocalDateTime createTime;
|
|
32
|
+
|
|
33
|
+
@TableField(fill = FieldFill.INSERT_UPDATE)
|
|
34
|
+
private LocalDateTime updateTime;
|
|
35
|
+
|
|
36
|
+
@TableLogic
|
|
37
|
+
@TableField("is_deleted")
|
|
38
|
+
private Integer isDeleted;
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 注解说明
|
|
43
|
+
|
|
44
|
+
| 注解 | 用途 | 规范 |
|
|
45
|
+
|------|------|------|
|
|
46
|
+
| `@TableName` | 表名映射 | 🔴 必须显式指定,使用 `t_` 前缀 |
|
|
47
|
+
| `@TableId` | 主键 | 🔴 必须指定,推荐 `IdType.ASSIGN_ID`(雪花算法) |
|
|
48
|
+
| `@TableField` | 字段映射 | 🟡 字段名与列名不一致时必须指定 |
|
|
49
|
+
| `@TableLogic` | 逻辑删除 | 🔴 必须使用逻辑删除,字段名 `is_deleted` |
|
|
50
|
+
| `FieldFill` | 自动填充 | 🔴 `createTime` 和 `updateTime` 必须自动填充 |
|
|
51
|
+
|
|
52
|
+
### ❌ 错误的 Entity 写法
|
|
53
|
+
|
|
54
|
+
```java
|
|
55
|
+
@Data
|
|
56
|
+
public class User { // ❌ 缺少 @TableName
|
|
57
|
+
private Long id; // ❌ 缺少 @TableId
|
|
58
|
+
private Date createTime; // ❌ 使用 Date 而非 LocalDateTime,缺少自动填充
|
|
59
|
+
// ❌ 缺少 isDeleted 逻辑删除字段
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 自动填充配置
|
|
66
|
+
|
|
67
|
+
```java
|
|
68
|
+
@Component
|
|
69
|
+
public class AvatarMetaObjectHandler implements MetaObjectHandler {
|
|
70
|
+
|
|
71
|
+
@Override
|
|
72
|
+
public void insertFill(MetaObject metaObject) {
|
|
73
|
+
this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class);
|
|
74
|
+
this.strictInsertFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@Override
|
|
78
|
+
public void updateFill(MetaObject metaObject) {
|
|
79
|
+
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Mapper 规范
|
|
87
|
+
|
|
88
|
+
```java
|
|
89
|
+
@Mapper
|
|
90
|
+
public interface UserMapper extends BaseMapper<UserEntity> {
|
|
91
|
+
// 简单 CRUD 直接继承 BaseMapper,无需手写
|
|
92
|
+
// 复杂查询使用 XML 或注解
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
- 🔴 必须继承 `BaseMapper<T>`
|
|
97
|
+
- 🔴 必须添加 `@Mapper` 注解(或在启动类加 `@MapperScan`)
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Service 规范
|
|
102
|
+
|
|
103
|
+
### ✅ 正确:继承 IService / ServiceImpl
|
|
104
|
+
|
|
105
|
+
```java
|
|
106
|
+
public interface UserService extends IService<UserEntity> {
|
|
107
|
+
// 自定义业务方法
|
|
108
|
+
UserResponse getUserDetail(Long id);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@Service
|
|
112
|
+
public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity>
|
|
113
|
+
implements UserService {
|
|
114
|
+
|
|
115
|
+
@Override
|
|
116
|
+
public UserResponse getUserDetail(Long id) {
|
|
117
|
+
UserEntity entity = getById(id);
|
|
118
|
+
// 转换为 DTO ...
|
|
119
|
+
return response;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### ❌ 错误:不继承 IService
|
|
125
|
+
|
|
126
|
+
```java
|
|
127
|
+
@Service
|
|
128
|
+
public class UserService { // ❌ 未继承 IService,无法使用内置 CRUD 方法
|
|
129
|
+
@Autowired
|
|
130
|
+
private UserMapper userMapper;
|
|
131
|
+
|
|
132
|
+
public UserEntity getById(Long id) {
|
|
133
|
+
return userMapper.selectById(id); // ❌ 手动调用 Mapper,重复造轮子
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 查询规范
|
|
141
|
+
|
|
142
|
+
### 🔴 LambdaQueryWrapper 优先
|
|
143
|
+
|
|
144
|
+
```java
|
|
145
|
+
// ✅ 正确:使用 LambdaQueryWrapper,类型安全
|
|
146
|
+
LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
|
|
147
|
+
wrapper.eq(UserEntity::getStatus, 1)
|
|
148
|
+
.like(StringUtils.isNotBlank(name), UserEntity::getUsername, name)
|
|
149
|
+
.orderByDesc(UserEntity::getCreateTime);
|
|
150
|
+
List<UserEntity> users = userMapper.selectList(wrapper);
|
|
151
|
+
|
|
152
|
+
// ❌ 错误:使用 QueryWrapper 字符串硬编码
|
|
153
|
+
QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
|
|
154
|
+
wrapper.eq("status", 1); // ❌ 字段名硬编码,重构不友好
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### 🔴 分页查询必须使用 Page<T>
|
|
158
|
+
|
|
159
|
+
```java
|
|
160
|
+
// ✅ 正确:使用 MyBatis Plus 分页
|
|
161
|
+
public IPage<UserEntity> pageQuery(int current, int size) {
|
|
162
|
+
Page<UserEntity> page = new Page<>(current, size);
|
|
163
|
+
LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
|
|
164
|
+
wrapper.eq(UserEntity::getStatus, 1);
|
|
165
|
+
return userMapper.selectPage(page, wrapper);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ❌ 错误:手写 LIMIT 分页
|
|
169
|
+
@Select("SELECT * FROM t_user WHERE status = 1 LIMIT #{offset}, #{size}")
|
|
170
|
+
List<UserEntity> pageQuery(@Param("offset") int offset, @Param("size") int size);
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 分页插件配置
|
|
174
|
+
|
|
175
|
+
```java
|
|
176
|
+
@Configuration
|
|
177
|
+
public class MyBatisPlusConfig {
|
|
178
|
+
|
|
179
|
+
@Bean
|
|
180
|
+
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
|
181
|
+
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
|
182
|
+
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
|
183
|
+
return interceptor;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 逻辑删除配置
|
|
191
|
+
|
|
192
|
+
```yaml
|
|
193
|
+
mybatis-plus:
|
|
194
|
+
global-config:
|
|
195
|
+
db-config:
|
|
196
|
+
logic-delete-field: isDeleted
|
|
197
|
+
logic-delete-value: 1
|
|
198
|
+
logic-not-delete-value: 0
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
配置后,所有继承 `BaseMapper` 的查询/更新/删除方法自动追加逻辑删除条件。
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## 性能反模式
|
|
206
|
+
|
|
207
|
+
### ❌ N+1 查询问题
|
|
208
|
+
|
|
209
|
+
```java
|
|
210
|
+
// ❌ 错误:循环查询数据库
|
|
211
|
+
List<OrderEntity> orders = orderMapper.selectList(null);
|
|
212
|
+
for (OrderEntity order : orders) {
|
|
213
|
+
UserEntity user = userMapper.selectById(order.getUserId()); // N 次查询!
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// ✅ 正确:批量查询
|
|
217
|
+
List<OrderEntity> orders = orderMapper.selectList(null);
|
|
218
|
+
Set<Long> userIds = orders.stream().map(OrderEntity::getUserId).collect(Collectors.toSet());
|
|
219
|
+
List<UserEntity> users = userMapper.selectBatchIds(userIds); // 1 次查询
|
|
220
|
+
Map<Long, UserEntity> userMap = users.stream().collect(Collectors.toMap(UserEntity::getId, Function.identity()));
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### ❌ 无 limit 的 selectList
|
|
224
|
+
|
|
225
|
+
```java
|
|
226
|
+
// ❌ 危险:无条件全表查询,数据量大时 OOM
|
|
227
|
+
List<UserEntity> allUsers = userMapper.selectList(null);
|
|
228
|
+
|
|
229
|
+
// ✅ 正确:始终带条件或分页
|
|
230
|
+
Page<UserEntity> page = new Page<>(1, 100);
|
|
231
|
+
IPage<UserEntity> users = userMapper.selectPage(page, wrapper);
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### ❌ 在循环中执行数据库操作
|
|
235
|
+
|
|
236
|
+
```java
|
|
237
|
+
// ❌ 错误:循环插入
|
|
238
|
+
for (UserEntity user : userList) {
|
|
239
|
+
userMapper.insert(user);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ✅ 正确:批量操作
|
|
243
|
+
userService.saveBatch(userList);
|
|
244
|
+
// 或指定批次大小
|
|
245
|
+
userService.saveBatch(userList, 500);
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## MyBatis Plus 使用检查清单
|
|
251
|
+
|
|
252
|
+
- [ ] Entity 是否标注 `@TableName` 并使用 `t_` 前缀
|
|
253
|
+
- [ ] 主键是否使用 `@TableId(type = IdType.ASSIGN_ID)`
|
|
254
|
+
- [ ] 是否包含 `createTime`、`updateTime` 自动填充字段
|
|
255
|
+
- [ ] 是否包含 `isDeleted` 逻辑删除字段
|
|
256
|
+
- [ ] Mapper 是否继承 `BaseMapper<T>`
|
|
257
|
+
- [ ] Service 是否继承 `IService<T>` / `ServiceImpl<M, T>`
|
|
258
|
+
- [ ] 查询是否使用 `LambdaQueryWrapper` 而非 `QueryWrapper`
|
|
259
|
+
- [ ] 分页是否使用 `Page<T>` 而非手写 LIMIT
|
|
260
|
+
- [ ] 是否存在 N+1 查询问题
|
|
261
|
+
- [ ] 是否存在无条件的 `selectList(null)` 全表查询
|
|
262
|
+
- [ ] 批量操作是否使用 `saveBatch` / `updateBatchById`
|
|
263
|
+
- [ ] 时间字段是否使用 `LocalDateTime` 而非 `Date`
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# 技术栈约束
|
|
2
|
+
|
|
3
|
+
> 规则类型: 🔴 强制执行
|
|
4
|
+
> 更新频率: 低(框架升级时更新)
|
|
5
|
+
> 相关规则: [architecture-redlines.md](architecture-redlines.md) | [version.md](version.md)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 必须使用的技术
|
|
10
|
+
|
|
11
|
+
| 模块 | 技术栈 | 版本 |
|
|
12
|
+
|------|--------|------|
|
|
13
|
+
| Java | OpenJDK | 21 |
|
|
14
|
+
| 构建工具 | Maven | 3.8.6+ |
|
|
15
|
+
| 框架核心 | Spring Boot | 3.5.3 |
|
|
16
|
+
| 微服务框架 | Spring Cloud | 2025.0.0 |
|
|
17
|
+
| 服务治理 | Spring Cloud Alibaba | 2023.0.3.2 |
|
|
18
|
+
| 注册中心 | Nacos | 通过 avatar-boot-starter-nacos |
|
|
19
|
+
| 服务调用 | OpenFeign | 通过 avatar-boot-starter-feign |
|
|
20
|
+
| 数据库 | MySQL | 通过 avatar-boot-starter-mysql |
|
|
21
|
+
| 缓存 | Redis | 通过 avatar-boot-starter-redis |
|
|
22
|
+
| ORM | MyBatis Plus | 3.5.15 |
|
|
23
|
+
| 工具库 | Hutool | 5.8.34 |
|
|
24
|
+
| JSON | Fastjson2 | 2.0.54 |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 核心原则
|
|
29
|
+
|
|
30
|
+
### 🔴 必须使用 Avatar Boot 封装组件
|
|
31
|
+
|
|
32
|
+
- ❌ **禁止**直接引用 Spring Boot、Spring Cloud 原生 starter
|
|
33
|
+
- ✅ **必须**使用 Avatar Boot 封装的 starter 组件
|
|
34
|
+
- ✅ **必须**配置 iFlytek Maven 仓库
|
|
35
|
+
|
|
36
|
+
### 🔴 必须使用 Jakarta 命名空间
|
|
37
|
+
|
|
38
|
+
- ❌ `javax.*` 已废弃
|
|
39
|
+
- ✅ `jakarta.*` 是正确的命名空间
|
|
40
|
+
|
|
41
|
+
> **详细配置、示例和版本信息请参考**: [version.md](version.md)
|