@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.
Files changed (77) hide show
  1. package/README.md +309 -0
  2. package/bin/cli.js +3 -0
  3. package/docs/plans/2026-03-12-avatar-boot-cli-design.md +73 -0
  4. package/docs/plans/2026-03-12-avatar-boot-cli-plan.md +681 -0
  5. package/package.json +28 -0
  6. package/src/index.js +78 -0
  7. package/src/prompts.js +78 -0
  8. package/src/template.js +37 -0
  9. package/src/transform.js +172 -0
  10. package/src/utils.js +34 -0
  11. package/templates/.claude/rules/architecture-redlines.md +146 -0
  12. package/templates/.claude/rules/code-review-standards.md +137 -0
  13. package/templates/.claude/rules/coding-standards.md +56 -0
  14. package/templates/.claude/rules/git-commit.md +59 -0
  15. package/templates/.claude/rules/layered-architecture.md +201 -0
  16. package/templates/.claude/rules/mybatis-plus.md +263 -0
  17. package/templates/.claude/rules/tech-stack.md +41 -0
  18. package/templates/.claude/rules/version.md +467 -0
  19. package/templates/.claude/settings.local.json +18 -0
  20. package/templates/.claude/skills/ai-tool-guide/SKILL.md +314 -0
  21. package/templates/.claude/skills/api-design/SKILL.md +200 -0
  22. package/templates/.claude/skills/api-doc-generator/SKILL.md +380 -0
  23. package/templates/.claude/skills/api-service-module-creator/SKILL.md +1114 -0
  24. package/templates/.claude/skills/avatar-boot-starter-feign/SKILL.md +243 -0
  25. package/templates/.claude/skills/avatar-boot-starter-job/SKILL.md +437 -0
  26. package/templates/.claude/skills/avatar-boot-starter-kafka/SKILL.md +580 -0
  27. package/templates/.claude/skills/avatar-boot-starter-mysql/SKILL.md +572 -0
  28. package/templates/.claude/skills/avatar-boot-starter-nacos/SKILL.md +901 -0
  29. package/templates/.claude/skills/avatar-boot-starter-oss/SKILL.md +594 -0
  30. package/templates/.claude/skills/avatar-boot-starter-redis/SKILL.md +586 -0
  31. package/templates/.claude/skills/avatar-boot-starter-rocketmq/SKILL.md +662 -0
  32. package/templates/.claude/skills/avatar-boot-starter-web/SKILL.md +1007 -0
  33. package/templates/.claude/skills/changelog-generator/SKILL.md +114 -0
  34. package/templates/.claude/skills/code-review/SKILL.md +239 -0
  35. package/templates/.claude/skills/crud-generator/SKILL.md +824 -0
  36. package/templates/.claude/skills/database-design/SKILL.md +377 -0
  37. package/templates/.claude/skills/deployment-config/SKILL.md +277 -0
  38. package/templates/.claude/skills/incident-analysis/SKILL.md +241 -0
  39. package/templates/.claude/skills/integration-test-generator/SKILL.md +496 -0
  40. package/templates/.claude/skills/prompt-engineering/SKILL.md +249 -0
  41. package/templates/.claude/skills/requirement-management/SKILL.md +244 -0
  42. package/templates/.claude/skills/security-audit/SKILL.md +330 -0
  43. package/templates/.claude/skills/test-case-design/SKILL.md +257 -0
  44. package/templates/.claude/skills/testing-workflow/SKILL.md +68 -0
  45. package/templates/.claude/skills/troubleshooting/SKILL.md +240 -0
  46. package/templates/CLAUDE.md +173 -0
  47. package/templates/README.md +303 -0
  48. package/templates/avatar-scaffold-api/pom.xml +41 -0
  49. package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/api/LoginFeignClient.java +40 -0
  50. package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/constant/LoginConstant.java +21 -0
  51. package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/dto/request/LoginRequest.java +17 -0
  52. package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/dto/request/RefreshTokenRequest.java +14 -0
  53. package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/dto/response/LoginResponse.java +31 -0
  54. package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/dto/response/TokenInfoResponse.java +25 -0
  55. package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/enums/LoginTypeEnum.java +23 -0
  56. package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/exception/LoginException.java +23 -0
  57. package/templates/avatar-scaffold-service/k8s-app/Dockerfile +14 -0
  58. package/templates/avatar-scaffold-service/k8s-app/Dockerfile-arm64 +14 -0
  59. package/templates/avatar-scaffold-service/packaging/assembly.xml +16 -0
  60. package/templates/avatar-scaffold-service/pom.xml +150 -0
  61. package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/Application.java +21 -0
  62. package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/config/LoginConfig.java +20 -0
  63. package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/controller/LoginController.java +37 -0
  64. package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/converter/LoginConverter.java +54 -0
  65. package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/feign/DemoFeign.java +21 -0
  66. package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/repository/entity/UserLoginEntity.java +33 -0
  67. package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/repository/entity/UserTokenEntity.java +39 -0
  68. package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/repository/mapper/UserLoginMapper.java +20 -0
  69. package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/service/LoginService.java +22 -0
  70. package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/service/impl/LoginServiceImpl.java +43 -0
  71. package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/utils/LoginUtils.java +31 -0
  72. package/templates/avatar-scaffold-service/src/main/resources/application-dev.yaml +29 -0
  73. package/templates/avatar-scaffold-service/src/main/resources/application-local.yaml +61 -0
  74. package/templates/avatar-scaffold-service/src/main/resources/application-prod.yaml +28 -0
  75. package/templates/avatar-scaffold-service/src/main/resources/application-test.yaml +28 -0
  76. package/templates/avatar-scaffold-service/src/main/resources/application.yaml +12 -0
  77. package/templates/pom.xml +98 -0
@@ -0,0 +1,824 @@
1
+ ---
2
+ name: crud-generator
3
+ description: |
4
+ 根据数据库表 DDL 或业务描述,自动生成完整的 CRUD 代码,包括 Entity、Mapper、Service、Controller、DTO 和 Feign API。
5
+ 触发词: CRUD, generate code, 增删改查, 代码生成, create entity, generate CRUD, 生成代码, scaffold
6
+ ---
7
+
8
+ # CRUD 代码生成技能 (CRUD Generator Skill)
9
+
10
+ ## 概述
11
+
12
+ 本技能根据数据库表 DDL 或表结构描述,自动生成符合 Avatar Boot 项目规范的完整 CRUD 代码。生成的代码遵循 API + Service 双模块架构,采用垂直功能组织方式。
13
+
14
+ > **与 api-service-module-creator 的区别**:本 Skill 专注于**从 DDL 快速生成单个功能的 CRUD 代码**(Entity/Mapper/Service/Controller/DTO)。如需**创建完整的 API + Service 双模块项目结构**(包括 pom.xml、包结构、配置文件),请使用 [api-service-module-creator](../api-service-module-creator/) Skill。
15
+
16
+ ---
17
+
18
+ ## 输入要求
19
+
20
+ ### 方式一:提供表 DDL
21
+
22
+ ```sql
23
+ CREATE TABLE t_user (
24
+ id BIGINT NOT NULL COMMENT '主键ID',
25
+ username VARCHAR(64) NOT NULL COMMENT '用户名',
26
+ email VARCHAR(128) DEFAULT NULL COMMENT '邮箱',
27
+ phone VARCHAR(20) DEFAULT NULL COMMENT '手机号',
28
+ status TINYINT NOT NULL DEFAULT 1 COMMENT '状态:0-禁用 1-启用',
29
+ create_time DATETIME NOT NULL COMMENT '创建时间',
30
+ update_time DATETIME NOT NULL COMMENT '更新时间',
31
+ is_deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除:0-未删除 1-已删除',
32
+ PRIMARY KEY (id),
33
+ UNIQUE KEY uk_username (username),
34
+ KEY idx_email (email)
35
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
36
+ ```
37
+
38
+ ### 方式二:提供表结构描述
39
+
40
+ ```
41
+ 表名: t_user (用户表)
42
+ 字段:
43
+ - username: 用户名, VARCHAR(64), 必填, 唯一
44
+ - email: 邮箱, VARCHAR(128), 可选
45
+ - phone: 手机号, VARCHAR(20), 可选
46
+ - status: 状态, TINYINT, 必填, 默认1 (0-禁用 1-启用)
47
+ ```
48
+
49
+ > 注意:`id`, `create_time`, `update_time`, `is_deleted` 为必需字段,无需在描述中指定,会自动添加。
50
+
51
+ ---
52
+
53
+ ## 输出文件列表
54
+
55
+ 以 `t_user` 表为例,生成的文件按垂直功能组织:
56
+
57
+ ### API 模块 (`avatar-api`)
58
+
59
+ | 文件 | 路径 |
60
+ |------|------|
61
+ | Request DTO | `com/iflytek/avatar/entity/request/UserCreateRequest.java` |
62
+ | Request DTO | `com/iflytek/avatar/entity/request/UserUpdateRequest.java` |
63
+ | Request DTO | `com/iflytek/avatar/entity/request/UserPageRequest.java` |
64
+ | Response DTO | `com/iflytek/avatar/entity/response/UserResponse.java` |
65
+ | Feign API | `com/iflytek/avatar/api/UserApi.java` |
66
+
67
+ ### Service 模块 (`avatar-service`)
68
+
69
+ | 文件 | 路径 |
70
+ |------|------|
71
+ | Entity | `com/iflytek/avatar/dao/beans/User.java` |
72
+ | Mapper | `com/iflytek/avatar/dao/mapper/UserMapper.java` |
73
+ | Service 接口 | `com/iflytek/avatar/service/UserService.java` |
74
+ | Service 实现 | `com/iflytek/avatar/service/impl/UserServiceImpl.java` |
75
+ | Controller | `com/iflytek/avatar/controller/UserController.java` |
76
+
77
+ ---
78
+
79
+ ## 代码模板
80
+
81
+ ### 1. Entity — `dao/beans/User.java`
82
+
83
+ ```java
84
+ package com.iflytek.avatar.dao.beans;
85
+
86
+ import com.baomidou.mybatisplus.annotation.*;
87
+ import lombok.Data;
88
+
89
+ import java.time.LocalDateTime;
90
+
91
+ /**
92
+ * 用户表实体
93
+ *
94
+ * @author avatar-generator
95
+ */
96
+ @Data
97
+ @TableName("t_user")
98
+ public class User {
99
+
100
+ /**
101
+ * 主键ID
102
+ */
103
+ @TableId(type = IdType.ASSIGN_ID)
104
+ private Long id;
105
+
106
+ /**
107
+ * 用户名
108
+ */
109
+ private String username;
110
+
111
+ /**
112
+ * 邮箱
113
+ */
114
+ private String email;
115
+
116
+ /**
117
+ * 手机号
118
+ */
119
+ private String phone;
120
+
121
+ /**
122
+ * 状态:0-禁用 1-启用
123
+ */
124
+ private Integer status;
125
+
126
+ /**
127
+ * 创建时间
128
+ */
129
+ @TableField(fill = FieldFill.INSERT)
130
+ private LocalDateTime createTime;
131
+
132
+ /**
133
+ * 更新时间
134
+ */
135
+ @TableField(fill = FieldFill.INSERT_UPDATE)
136
+ private LocalDateTime updateTime;
137
+
138
+ /**
139
+ * 逻辑删除:0-未删除 1-已删除
140
+ */
141
+ @TableLogic
142
+ private Integer isDeleted;
143
+ }
144
+ ```
145
+
146
+ ### 2. Mapper — `dao/mapper/UserMapper.java`
147
+
148
+ ```java
149
+ package com.iflytek.avatar.dao.mapper;
150
+
151
+ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
152
+ import com.iflytek.avatar.dao.beans.User;
153
+ import org.apache.ibatis.annotations.Mapper;
154
+
155
+ /**
156
+ * 用户表 Mapper 接口
157
+ *
158
+ * @author avatar-generator
159
+ */
160
+ @Mapper
161
+ public interface UserMapper extends BaseMapper<User> {
162
+
163
+ }
164
+ ```
165
+
166
+ ### 3. Service 接口 — `service/UserService.java`
167
+
168
+ ```java
169
+ package com.iflytek.avatar.service;
170
+
171
+ import com.baomidou.mybatisplus.core.metadata.IPage;
172
+ import com.baomidou.mybatisplus.extension.service.IService;
173
+ import com.iflytek.avatar.dao.beans.User;
174
+ import com.iflytek.avatar.entity.request.UserCreateRequest;
175
+ import com.iflytek.avatar.entity.request.UserPageRequest;
176
+ import com.iflytek.avatar.entity.request.UserUpdateRequest;
177
+ import com.iflytek.avatar.entity.response.UserResponse;
178
+
179
+ /**
180
+ * 用户表 Service 接口
181
+ *
182
+ * @author avatar-generator
183
+ */
184
+ public interface UserService extends IService<User> {
185
+
186
+ /**
187
+ * 创建用户
188
+ *
189
+ * @param request 创建请求
190
+ * @return 用户信息
191
+ */
192
+ UserResponse create(UserCreateRequest request);
193
+
194
+ /**
195
+ * 根据ID查询用户
196
+ *
197
+ * @param id 用户ID
198
+ * @return 用户信息
199
+ */
200
+ UserResponse getDetail(Long id);
201
+
202
+ /**
203
+ * 更新用户
204
+ *
205
+ * @param id 用户ID
206
+ * @param request 更新请求
207
+ * @return 用户信息
208
+ */
209
+ UserResponse update(Long id, UserUpdateRequest request);
210
+
211
+ /**
212
+ * 删除用户
213
+ *
214
+ * @param id 用户ID
215
+ */
216
+ void delete(Long id);
217
+
218
+ /**
219
+ * 分页查询用户
220
+ *
221
+ * @param request 分页请求
222
+ * @return 分页结果
223
+ */
224
+ IPage<UserResponse> page(UserPageRequest request);
225
+ }
226
+ ```
227
+
228
+ ### 4. ServiceImpl — `service/impl/UserServiceImpl.java`
229
+
230
+ ```java
231
+ package com.iflytek.avatar.service.impl;
232
+
233
+ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
234
+ import com.baomidou.mybatisplus.core.metadata.IPage;
235
+ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
236
+ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
237
+ import com.iflytek.avatar.dao.beans.User;
238
+ import com.iflytek.avatar.dao.mapper.UserMapper;
239
+ import com.iflytek.avatar.entity.request.UserCreateRequest;
240
+ import com.iflytek.avatar.entity.request.UserPageRequest;
241
+ import com.iflytek.avatar.entity.request.UserUpdateRequest;
242
+ import com.iflytek.avatar.entity.response.UserResponse;
243
+ import com.iflytek.avatar.service.UserService;
244
+ import lombok.RequiredArgsConstructor;
245
+ import org.springframework.beans.BeanUtils;
246
+ import org.springframework.stereotype.Service;
247
+ import org.springframework.transaction.annotation.Transactional;
248
+
249
+ import java.util.Objects;
250
+
251
+ /**
252
+ * 用户表 Service 实现类
253
+ *
254
+ * @author avatar-generator
255
+ */
256
+ @Service
257
+ @RequiredArgsConstructor
258
+ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
259
+
260
+ @Override
261
+ @Transactional(rollbackFor = Exception.class)
262
+ public UserResponse create(UserCreateRequest request) {
263
+ User user = new User();
264
+ BeanUtils.copyProperties(request, user);
265
+ this.save(user);
266
+ return toResponse(user);
267
+ }
268
+
269
+ @Override
270
+ @Transactional(readOnly = true)
271
+ public UserResponse getDetail(Long id) {
272
+ User user = this.getById(id);
273
+ if (Objects.isNull(user)) {
274
+ throw new RuntimeException("用户不存在,ID: " + id);
275
+ }
276
+ return toResponse(user);
277
+ }
278
+
279
+ @Override
280
+ @Transactional(rollbackFor = Exception.class)
281
+ public UserResponse update(Long id, UserUpdateRequest request) {
282
+ User user = this.getById(id);
283
+ if (Objects.isNull(user)) {
284
+ throw new RuntimeException("用户不存在,ID: " + id);
285
+ }
286
+ BeanUtils.copyProperties(request, user);
287
+ user.setId(id);
288
+ this.updateById(user);
289
+ return toResponse(user);
290
+ }
291
+
292
+ @Override
293
+ @Transactional(rollbackFor = Exception.class)
294
+ public void delete(Long id) {
295
+ User user = this.getById(id);
296
+ if (Objects.isNull(user)) {
297
+ throw new RuntimeException("用户不存在,ID: " + id);
298
+ }
299
+ this.removeById(id);
300
+ }
301
+
302
+ @Override
303
+ @Transactional(readOnly = true)
304
+ public IPage<UserResponse> page(UserPageRequest request) {
305
+ Page<User> page = new Page<>(request.getPageNum(), request.getPageSize());
306
+ LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
307
+
308
+ // 条件查询(按需添加)
309
+ if (request.getUsername() != null) {
310
+ wrapper.like(User::getUsername, request.getUsername());
311
+ }
312
+ if (request.getStatus() != null) {
313
+ wrapper.eq(User::getStatus, request.getStatus());
314
+ }
315
+
316
+ // 默认按创建时间倒序
317
+ wrapper.orderByDesc(User::getCreateTime);
318
+
319
+ IPage<User> result = this.page(page, wrapper);
320
+ return result.convert(this::toResponse);
321
+ }
322
+
323
+ /**
324
+ * Entity 转 Response DTO
325
+ */
326
+ private UserResponse toResponse(User user) {
327
+ UserResponse response = new UserResponse();
328
+ BeanUtils.copyProperties(user, response);
329
+ return response;
330
+ }
331
+ }
332
+ ```
333
+
334
+ ### 5. Controller — `controller/UserController.java`
335
+
336
+ ```java
337
+ package com.iflytek.avatar.controller;
338
+
339
+ import com.baomidou.mybatisplus.core.metadata.IPage;
340
+ import com.iflytek.avatar.common.result.Result;
341
+ import com.iflytek.avatar.entity.request.UserCreateRequest;
342
+ import com.iflytek.avatar.entity.request.UserPageRequest;
343
+ import com.iflytek.avatar.entity.request.UserUpdateRequest;
344
+ import com.iflytek.avatar.entity.response.UserResponse;
345
+ import com.iflytek.avatar.service.UserService;
346
+ import jakarta.validation.Valid;
347
+ import lombok.RequiredArgsConstructor;
348
+ import org.springframework.web.bind.annotation.*;
349
+
350
+ /**
351
+ * 用户管理接口
352
+ *
353
+ * @author avatar-generator
354
+ */
355
+ @RestController
356
+ @RequestMapping("/api/v1/users")
357
+ @RequiredArgsConstructor
358
+ public class UserController {
359
+
360
+ private final UserService userService;
361
+
362
+ /**
363
+ * 创建用户
364
+ */
365
+ @PostMapping
366
+ public Result<UserResponse> create(@Valid @RequestBody UserCreateRequest request) {
367
+ return Result.success(userService.create(request));
368
+ }
369
+
370
+ /**
371
+ * 根据ID查询用户
372
+ */
373
+ @GetMapping("/{id}")
374
+ public Result<UserResponse> getById(@PathVariable Long id) {
375
+ return Result.success(userService.getDetail(id));
376
+ }
377
+
378
+ /**
379
+ * 更新用户
380
+ */
381
+ @PutMapping("/{id}")
382
+ public Result<UserResponse> update(@PathVariable Long id,
383
+ @Valid @RequestBody UserUpdateRequest request) {
384
+ return Result.success(userService.update(id, request));
385
+ }
386
+
387
+ /**
388
+ * 删除用户
389
+ */
390
+ @DeleteMapping("/{id}")
391
+ public Result<Void> delete(@PathVariable Long id) {
392
+ userService.delete(id);
393
+ return Result.success();
394
+ }
395
+
396
+ /**
397
+ * 分页查询用户
398
+ */
399
+ @GetMapping
400
+ public Result<IPage<UserResponse>> page(@Valid UserPageRequest request) {
401
+ return Result.success(userService.page(request));
402
+ }
403
+ }
404
+ ```
405
+
406
+ ### 6. Request DTO — `entity/request/UserCreateRequest.java`
407
+
408
+ ```java
409
+ package com.iflytek.avatar.entity.request;
410
+
411
+ import jakarta.validation.constraints.NotBlank;
412
+ import jakarta.validation.constraints.Size;
413
+ import lombok.Data;
414
+
415
+ /**
416
+ * 用户创建请求
417
+ *
418
+ * @author avatar-generator
419
+ */
420
+ @Data
421
+ public class UserCreateRequest {
422
+
423
+ /**
424
+ * 用户名
425
+ */
426
+ @NotBlank(message = "用户名不能为空")
427
+ @Size(max = 64, message = "用户名长度不能超过64个字符")
428
+ private String username;
429
+
430
+ /**
431
+ * 邮箱
432
+ */
433
+ @Size(max = 128, message = "邮箱长度不能超过128个字符")
434
+ private String email;
435
+
436
+ /**
437
+ * 手机号
438
+ */
439
+ @Size(max = 20, message = "手机号长度不能超过20个字符")
440
+ private String phone;
441
+
442
+ /**
443
+ * 状态:0-禁用 1-启用
444
+ */
445
+ private Integer status;
446
+ }
447
+ ```
448
+
449
+ ### 7. Request DTO — `entity/request/UserUpdateRequest.java`
450
+
451
+ ```java
452
+ package com.iflytek.avatar.entity.request;
453
+
454
+ import jakarta.validation.constraints.Size;
455
+ import lombok.Data;
456
+
457
+ /**
458
+ * 用户更新请求
459
+ *
460
+ * @author avatar-generator
461
+ */
462
+ @Data
463
+ public class UserUpdateRequest {
464
+
465
+ /**
466
+ * 用户名
467
+ */
468
+ @Size(max = 64, message = "用户名长度不能超过64个字符")
469
+ private String username;
470
+
471
+ /**
472
+ * 邮箱
473
+ */
474
+ @Size(max = 128, message = "邮箱长度不能超过128个字符")
475
+ private String email;
476
+
477
+ /**
478
+ * 手机号
479
+ */
480
+ @Size(max = 20, message = "手机号长度不能超过20个字符")
481
+ private String phone;
482
+
483
+ /**
484
+ * 状态:0-禁用 1-启用
485
+ */
486
+ private Integer status;
487
+ }
488
+ ```
489
+
490
+ ### 8. Request DTO — `entity/request/UserPageRequest.java`
491
+
492
+ ```java
493
+ package com.iflytek.avatar.entity.request;
494
+
495
+ import jakarta.validation.constraints.Max;
496
+ import jakarta.validation.constraints.Min;
497
+ import lombok.Data;
498
+
499
+ /**
500
+ * 用户分页查询请求
501
+ *
502
+ * @author avatar-generator
503
+ */
504
+ @Data
505
+ public class UserPageRequest {
506
+
507
+ /**
508
+ * 页码,默认1
509
+ */
510
+ @Min(value = 1, message = "页码最小为1")
511
+ private Integer pageNum = 1;
512
+
513
+ /**
514
+ * 每页条数,默认10
515
+ */
516
+ @Min(value = 1, message = "每页条数最小为1")
517
+ @Max(value = 100, message = "每页条数最大为100")
518
+ private Integer pageSize = 10;
519
+
520
+ /**
521
+ * 用户名(模糊查询)
522
+ */
523
+ private String username;
524
+
525
+ /**
526
+ * 状态(精确查询)
527
+ */
528
+ private Integer status;
529
+ }
530
+ ```
531
+
532
+ ### 9. Response DTO — `entity/response/UserResponse.java`
533
+
534
+ ```java
535
+ package com.iflytek.avatar.entity.response;
536
+
537
+ import lombok.Data;
538
+
539
+ import java.time.LocalDateTime;
540
+
541
+ /**
542
+ * 用户响应
543
+ *
544
+ * @author avatar-generator
545
+ */
546
+ @Data
547
+ public class UserResponse {
548
+
549
+ /**
550
+ * 主键ID
551
+ */
552
+ private Long id;
553
+
554
+ /**
555
+ * 用户名
556
+ */
557
+ private String username;
558
+
559
+ /**
560
+ * 邮箱
561
+ */
562
+ private String email;
563
+
564
+ /**
565
+ * 手机号
566
+ */
567
+ private String phone;
568
+
569
+ /**
570
+ * 状态:0-禁用 1-启用
571
+ */
572
+ private Integer status;
573
+
574
+ /**
575
+ * 创建时间
576
+ */
577
+ private LocalDateTime createTime;
578
+
579
+ /**
580
+ * 更新时间
581
+ */
582
+ private LocalDateTime updateTime;
583
+ }
584
+ ```
585
+
586
+ ### 10. Feign API 接口 — `api/UserApi.java`
587
+
588
+ ```java
589
+ package com.iflytek.avatar.api;
590
+
591
+ import com.baomidou.mybatisplus.core.metadata.IPage;
592
+ import com.iflytek.avatar.common.result.Result;
593
+ import com.iflytek.avatar.entity.request.UserCreateRequest;
594
+ import com.iflytek.avatar.entity.request.UserPageRequest;
595
+ import com.iflytek.avatar.entity.request.UserUpdateRequest;
596
+ import com.iflytek.avatar.entity.response.UserResponse;
597
+ import org.springframework.cloud.openfeign.FeignClient;
598
+ import org.springframework.web.bind.annotation.*;
599
+
600
+ /**
601
+ * 用户服务 Feign API
602
+ *
603
+ * @author avatar-generator
604
+ */
605
+ @FeignClient(name = "avatar-service", path = "/api/v1/users")
606
+ public interface UserApi {
607
+
608
+ @PostMapping
609
+ Result<UserResponse> create(@RequestBody UserCreateRequest request);
610
+
611
+ @GetMapping("/{id}")
612
+ Result<UserResponse> getById(@PathVariable("id") Long id);
613
+
614
+ @PutMapping("/{id}")
615
+ Result<UserResponse> update(@PathVariable("id") Long id,
616
+ @RequestBody UserUpdateRequest request);
617
+
618
+ @DeleteMapping("/{id}")
619
+ Result<Void> delete(@PathVariable("id") Long id);
620
+
621
+ @GetMapping
622
+ Result<IPage<UserResponse>> page(UserPageRequest request);
623
+ }
624
+ ```
625
+
626
+ ---
627
+
628
+ ## 单元测试骨架
629
+
630
+ ```java
631
+ package com.iflytek.avatar.service;
632
+
633
+ import com.iflytek.avatar.dao.beans.User;
634
+ import com.iflytek.avatar.dao.mapper.UserMapper;
635
+ import com.iflytek.avatar.entity.request.UserCreateRequest;
636
+ import com.iflytek.avatar.entity.response.UserResponse;
637
+ import com.iflytek.avatar.service.impl.UserServiceImpl;
638
+ import org.junit.jupiter.api.DisplayName;
639
+ import org.junit.jupiter.api.Test;
640
+ import org.junit.jupiter.api.extension.ExtendWith;
641
+ import org.mockito.InjectMocks;
642
+ import org.mockito.Mock;
643
+ import org.mockito.junit.jupiter.MockitoExtension;
644
+
645
+ import static org.junit.jupiter.api.Assertions.*;
646
+ import static org.mockito.ArgumentMatchers.any;
647
+ import static org.mockito.Mockito.*;
648
+
649
+ /**
650
+ * UserService 单元测试
651
+ */
652
+ @ExtendWith(MockitoExtension.class)
653
+ class UserServiceTest {
654
+
655
+ @InjectMocks
656
+ private UserServiceImpl userService;
657
+
658
+ @Mock
659
+ private UserMapper userMapper;
660
+
661
+ @Test
662
+ @DisplayName("创建用户 - 正常流程")
663
+ void create_shouldReturnUserResponse_whenValidRequest() {
664
+ // Given
665
+ UserCreateRequest request = new UserCreateRequest();
666
+ request.setUsername("testuser");
667
+ request.setEmail("test@example.com");
668
+
669
+ when(userMapper.insert(any(User.class))).thenReturn(1);
670
+
671
+ // When
672
+ UserResponse response = userService.create(request);
673
+
674
+ // Then
675
+ assertNotNull(response);
676
+ assertEquals("testuser", response.getUsername());
677
+ verify(userMapper, times(1)).insert(any(User.class));
678
+ }
679
+
680
+ @Test
681
+ @DisplayName("查询用户 - 用户不存在")
682
+ void getDetail_shouldThrowException_whenUserNotFound() {
683
+ // Given
684
+ Long userId = 999L;
685
+ when(userMapper.selectById(userId)).thenReturn(null);
686
+
687
+ // When & Then
688
+ assertThrows(RuntimeException.class, () -> userService.getDetail(userId));
689
+ }
690
+
691
+ @Test
692
+ @DisplayName("删除用户 - 正常流程")
693
+ void delete_shouldSucceed_whenUserExists() {
694
+ // Given
695
+ Long userId = 1L;
696
+ User user = new User();
697
+ user.setId(userId);
698
+ when(userMapper.selectById(userId)).thenReturn(user);
699
+ when(userMapper.deleteById(userId)).thenReturn(1);
700
+
701
+ // When
702
+ userService.delete(userId);
703
+
704
+ // Then
705
+ verify(userMapper, times(1)).deleteById(userId);
706
+ }
707
+
708
+ // TODO: 补充更多测试用例
709
+ // - 更新用户 - 正常流程
710
+ // - 更新用户 - 用户不存在
711
+ // - 分页查询 - 无条件
712
+ // - 分页查询 - 带条件
713
+ }
714
+ ```
715
+
716
+ ---
717
+
718
+ ## 自定义选项
719
+
720
+ ### 指定生成文件范围
721
+
722
+ 用户可以指定只生成部分文件:
723
+
724
+ ```
725
+ 请根据以下 DDL 只生成 Entity 和 Mapper:
726
+ CREATE TABLE t_order (...);
727
+ ```
728
+
729
+ ### 自定义字段映射
730
+
731
+ 用户可以指定字段的特殊处理:
732
+
733
+ ```
734
+ 请生成 CRUD 代码,其中:
735
+ - price 字段使用 BigDecimal 类型
736
+ - status 字段生成枚举类 OrderStatus
737
+ - description 字段不在列表查询中返回
738
+ ```
739
+
740
+ ### 自定义业务异常
741
+
742
+ 生成代码时,将 `RuntimeException` 替换为项目的自定义业务异常类:
743
+
744
+ ```java
745
+ // 替换前
746
+ throw new RuntimeException("用户不存在,ID: " + id);
747
+
748
+ // 替换后(根据项目实际异常类调整)
749
+ throw new BusinessException(ErrorCode.USER_NOT_FOUND, "用户不存在,ID: " + id);
750
+ ```
751
+
752
+ ---
753
+
754
+ ## 命名转换规则
755
+
756
+ | 数据库命名 | Java 命名 | 示例 |
757
+ |-----------|-----------|------|
758
+ | 表名 `t_user_order` | 类名 `UserOrder` | 去掉 `t_` 前缀,转 PascalCase |
759
+ | 列名 `user_name` | 字段名 `userName` | 转 camelCase |
760
+ | 表名 `t_user` | URL `/api/v1/users` | 去掉 `t_` 前缀,复数形式 |
761
+ | 表名 `t_user` | Mapper `UserMapper` | 类名 + Mapper |
762
+ | 表名 `t_user` | Service `UserService` | 类名 + Service |
763
+ | 表名 `t_user` | ServiceImpl `UserServiceImpl` | 类名 + ServiceImpl |
764
+ | 表名 `t_user` | Controller `UserController` | 类名 + Controller |
765
+
766
+ ---
767
+
768
+ ## 依赖规则
769
+
770
+ 生成代码时必须遵循以下规则文件中的规范:
771
+
772
+ - **分层架构规范**: 确保代码按 Controller → Service → Mapper 分层
773
+ - **MyBatis Plus 规范**: 确保 Entity 注解、Mapper 继承、Service 继承正确
774
+ - **编码规范**: 确保命名、注释、格式符合项目标准
775
+
776
+ ---
777
+
778
+ ## 最佳实践
779
+
780
+ 1. **先设计 DDL,再生成代码** — 确保表结构设计合理后再生成
781
+ 2. **生成后检查并调整** — 自动生成的代码是起点,需根据业务需求调整
782
+ 3. **补充业务逻辑** — 生成的代码只包含基础 CRUD,复杂业务逻辑需手动补充
783
+ 4. **完善单元测试** — 基于测试骨架补充完整的测试用例
784
+ 5. **敏感字段处理** — 检查 Response DTO,确保密码等敏感字段不暴露
785
+ 6. **校验规则完善** — 根据业务需求补充 Request DTO 中的校验注解
786
+
787
+ ---
788
+
789
+ ## 常见问题排查
790
+
791
+ ### Q: 生成的 Entity 字段类型与数据库不匹配?
792
+
793
+ 常见的类型映射关系:
794
+
795
+ | MySQL 类型 | Java 类型 |
796
+ |-----------|-----------|
797
+ | BIGINT | Long |
798
+ | INT / INTEGER | Integer |
799
+ | TINYINT | Integer |
800
+ | VARCHAR / CHAR | String |
801
+ | TEXT / LONGTEXT | String |
802
+ | DECIMAL | BigDecimal |
803
+ | DATETIME | LocalDateTime |
804
+ | DATE | LocalDate |
805
+ | TIME | LocalTime |
806
+ | BIT(1) / BOOLEAN | Boolean |
807
+
808
+ ### Q: 如何处理表关联查询?
809
+
810
+ 基础 CRUD 不包含关联查询。如需关联查询:
811
+ 1. 在 Mapper 中添加自定义 SQL 或 XML 映射
812
+ 2. 在 Service 中组装关联数据
813
+ 3. 在 Response DTO 中添加关联字段
814
+
815
+ ### Q: 如何支持批量操作?
816
+
817
+ 在 Service 接口中添加批量方法:
818
+
819
+ ```java
820
+ void batchCreate(List<UserCreateRequest> requests);
821
+ void batchDelete(List<Long> ids);
822
+ ```
823
+
824
+ 使用 MyBatis Plus 的 `saveBatch` / `removeBatchByIds` 实现。