Files
offerpai_backend/.kiro/steering/代码开发风格文档.md
T
2026-05-19 11:49:38 +08:00

155 lines
7.5 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.
---
inclusion: manual
---
# 代码开发风格文档
本项目为 Spring Boot + MyBatis-Plus 的 Java 17 多模块后端项目,基础包名 `org.jiayunet`
## 项目结构
- `common` — 公共模块:配置、拦截器、工具类、统一响应、异常体系
- `client-api` — C 端接口模块,依赖 manager
- `manager` — 业务共享模块:实体、Mapper、业务服务,B 端和 C 端共用,依赖 common
- 各模块内按职责分包:`controller``service``pojo`dto/vo/po/param)、`mapper``config``aop``annotation``tool``constant``interceptor`
## 命名约定
### 类命名
- 服务层以 `Service` 结尾,如 `LoginService``SmsService`
- DTO 以 `Dto` 结尾,VO 以 `Vo` 结尾,Param 以 `Param` 结尾,PO 无后缀直接用业务名
- Controller 以 `Controller` 结尾
- 工具类以 `Tool` 结尾,如 `RedisServerTool``HttpIpTool`
- 配置类以 `Config``Conf` 结尾
- 切面以 `Aspect` 结尾,拦截器以 `Interceptor` 结尾,过滤器以 `Filter` 结尾
- 能力/抽象类以 `Ability` 结尾,如 `EmailAbility`
- 枚举以 `Enum` 结尾,枚举接口以 `Operations` 结尾
### 常量
- Redis key 前缀用 `interface` 定义常量,集中在 `PreRedisKeyName`
- 自定义配置属性统一用 `app.` 前缀分组
## 注解与依赖注入
- Controller 层:`@RestController` + `@RequestMapping`,构造器注入(`@AllArgsConstructor`
- Service 层:`@Service`,字段注入(`@Autowired`
- 配置值:`@Value("${app.xxx:默认值}")`,始终提供默认值
- 参数校验:类上 `@Validated`,字段上 `@NotBlank``@Pattern`
- 写操作方法加 `@Transactional(rollbackFor = Exception.class)`
- 所有 POJO 使用 `@Data`,需要日志的类加 `@Slf4j`
## 注释规范
- 类注释 Javadoc 格式,标注 `@author zk`
- 方法注释 `/** */`,简洁描述功能
- 字段注释 `/** */` 单行格式
### PO 实体类注释
- 类注释说明对应的表名和用途
- 特殊字段(状态码、标志位、枚举值等)在注释中说明每个值的含义,如 `/** 状态 0=正常 1=禁用 */`
### Service 类注释
- 类注释说明该服务的主要功能
- 类注释中列出依赖的其他模块/服务,以及使用到的表和使用目的,格式示例:
```java
/**
* 登录服务
* <p>依赖:SmsService(验证码发送与校验)、UserRegisterService(自动注册)</p>
* <p>使用表:bg_user(查询/创建用户)</p>
*
* @author zk
*/
```
- 每个方法用 `/** */` 简要说明逻辑流程,复杂方法可分步骤描述,格式示例:
```java
/**
* 短信验证码登录
* <p>1. 校验验证码 2. 查询用户,不存在则自动注册 3. 检查用户状态 4. 生成JWT并写入Redis 5. 设置Cookie</p>
*/
```
## POJO 规范
- Param:入参对象 + 校验注解,放在 `pojo/param/{功能模块}/` 下,功能模块一般是对应 Service 类名的简写,如 `pojo/param/login/SmsLoginParam.java`
- DTO:出参对象(接口返回给前端的数据),放在 `pojo/dto/{功能模块}/` 下,如 `pojo/dto/login/SmsLoginDto.java`
- VO:多场景共享的复合对象,放在 `pojo/vo/` 下,如 `pojo/vo/RouteMenuVo.java`
- PO:对应数据库表字段,统一放在 `manager` 模块的 `pojo/po/` 下
## 获取当前登录用户
- 通过 `UserSecurityTool.getUserId()` 静态方法获取当前登录用户 ID
- 底层从 `SecurityContextHolder` 中取值,无需传参,任何层都可直接调用
## 分页规范
- 分页入参继承或组合 `PageParam`(位于 common 模块),包含 `pageNum`(默认1)和 `pageSize`(默认10,最大100
- 通过 `pageParam.toPage()` 转换为 MyBatis-Plus 的 `Page<T>` 对象
- 分页出参统一使用 `PageResult<T>`,通过 `PageResult.from(page)` 从 MyBatis-Plus 分页结果构建
- 带业务筛选条件的分页查询,Param 对象中包含分页参数和筛选字段,放在 `pojo/param/{功能模块}/` 下
## 接口规范
- Controller 只负责参数接收和调用 Service,不写业务逻辑
- 无需鉴权的接口放在 `/public` 前缀下
- POST 用 `@PostMapping`GET 用 `@GetMapping` ...
- 复杂参数 `@Validated @RequestBody`,简单参数 `@RequestParam`
- Controller 方法直接返回业务对象,由 `UnifiedResponseBodyAdvice` 自动包装为 `UnifiedResponse`
## 异常处理
- 业务异常统一使用 `throw new BusinessException(BusinessExpCodeEnum.XXX, "描述")` 抛出
- 简单断言使用 Spring 的 `Assert.hasText()`、`Assert.notNull()` 等
- 不要 catch 后吞掉异常,交由 `GlobalExceptionAdvice` 统一处理
## Redis 使用规范
- 统一通过 `RedisServiceTool` 操作,不直接使用 `RedisTemplate`
- key 自动拼接应用名前缀:`{appName}:{业务key}`
- 值统一 JSON 序列化
- 设置 TTL 时使用 `TimeUnit` 明确单位
## 数据库设计风格
- 表名以 `bg_` 前缀,下划线命名,如 `bg_user`、`bg_route_menu`
- 主键 `id`,类型 `Long`,策略 `ASSIGN_ID`(雪花算法)
- 时间字段使用 `Instant` 类型,包含 `createTime` 和 `updateTime`
- 逻辑删除字段 `isDelete`,类型 `Long`0=正常,非0=删除(`@TableLogic(value = "0", delval = "UNIX_TIMESTAMP()")`
- 状态字段用 `Integer`0/1 表示,注释中说明含义
- PO 类加 `@TableName(value = "bg_xxx")`,主键加 `@TableId(type = IdType.ASSIGN_ID)`
- 查询使用 `LambdaQueryWrapper` 构建条件,避免硬编码字段名
- 简单的 CRUD 直接使用 MyBatis-Plus 的 `BaseMapper` 方法和 `LambdaQueryWrapper`,只有复杂查询(多表关联、子查询等)才写 Mapper XML SQL
- Mapper 接口继承 `BaseMapper<T>`
### JSON 字段规范
- 数据库中存储 JSON 的字段,PO 中必须使用对应的 Java 类型(`List<String>`、`List<Long>`、`List<XxxObject>` 等),不使用 `String`
- 通过 MyBatis-Plus 的 `@TableField(typeHandler = JacksonTypeHandler.class)` 注解实现自动序列化/反序列化
- 含有 TypeHandler 字段的 PO`@TableName` 必须加 `autoResultMap = true`,如 `@TableName(value = "bg_xxx", autoResultMap = true)`
- JSON 数组存简单值用 `List<String>` 或 `List<Long>`,存复杂结构则抽象为独立的 VO 类(如 `DescriptionParagraph`),放在 `manager/pojo/vo/` 下
- Param 和 Dto 中对应字段直接使用相同的 Java 类型,Controller 层通过 `BeanUtils.copyProperties` 直接拷贝,不做手动 JSON 转换
## 代码格式规范
### 紧凑风格
- 避免过度换行,保持代码紧凑易读
- Lambda 表达式和 Stream 操作尽量写在一行,除非超过 120 字符
- 方法参数列表较多时,可适当换行但保持紧凑,每行放多个参数
- 字符串拼接优先写在一行,除非过长影响可读性
### 示例
**推荐(紧凑风格):**
```java
// 查询语句一行
List<JobCategory> categories = jobCategoryMapper.selectList(new LambdaQueryWrapper<JobCategory>().eq(JobCategory::getLevel, 2));
// Stream 操作一行
List<Long> ids = categories.stream().map(JobCategory::getId).collect(Collectors.toList());
// 方法参数紧凑排列
private List<Long> identifyCategories(UserProfile profile, List<UserProfileEducation> educationList,
List<UserProfileWork> workList, List<UserProfileInternship> internshipList,
List<UserProfileProject> projectList, List<UserProfileCompetition> competitionList) {
// 字符串拼接一行
String userMessage = "【用户个人资料】\n" + profileJson + "\n\n【二级岗位分类列表】\n" + categoryText;