first commit

This commit is contained in:
xiang
2026-07-25 23:45:09 +08:00
commit c7bd957e6f
47 changed files with 3870 additions and 0 deletions
@@ -0,0 +1,62 @@
# 命名、格式与注释
## 命名
- **必须**:类、接口和枚举使用 `UpperCamelCase`;方法、参数、字段和局部变量使用 `lowerCamelCase`;常量使用语义完整的 `UPPER_SNAKE_CASE`
- **必须**:包名全小写,以稳定的组织与业务域命名;遵循项目现有单复数约定。
- **必须**:命名不得以 `_``$` 开头、结尾,不得使用中文、纯拼音或中英拼音混写。国际通用专名除外。
- **必须**:抽象基类使用 `Abstract` 或项目约定前缀;异常以 `Exception` 结尾;测试类遵循项目测试框架的现有命名。
- **必须**:避免无意义缩写、单字母业务变量和误导性名称。循环索引等极小作用域变量可以使用惯用短名。
- **必须**:Bean/序列化对象的布尔属性命名必须验证框架映射;默认不以 `is` 命名字段,访问器可按 JavaBeans 约定使用 `isXxx()`
- **推荐**DO、DTO、BO、VO、PO 等后缀只在项目已经定义其语义时使用,不自行发明相邻概念。
- **推荐**:实现设计模式时让类名表达职责,如 `OrderFactory`;不要仅为套用模式而改名。
## 常量与字面量
- **必须**:禁止散落的业务魔法值;提取为有领域含义的常量、枚举或值对象。
- **必须**`long` 字面量使用大写 `L`
- **必须**:不得用一个“万能常量类”承载所有模块常量;按模块和职责控制可见性。
- **推荐**:仅在真正固定且跨实例共享时声明 `static final`;不要把可变集合伪装成常量。
- **推荐**:状态和类型码优先使用有行为约束的枚举或值对象,同时保持对外协议兼容。
## 格式
- **必须**:服从项目 formatter、Checkstyle 或编辑器配置;不得因本文件偏好覆盖自动化格式规则。
- **必须**:控制语句始终使用大括号;关键字与左括号间保留空格;运算符两侧保留空格。
- **必须**:默认使用 4 空格缩进且不使用 Tab;项目 formatter 另有规定时从项目。
- **推荐**:单行不超过 120 字符;import 和自动生成代码按工具配置处理。
- **推荐**:新增方法原则上不超过 80 行,新增类原则上不超过 500 行。生成代码、声明型配置或框架限制可例外,但应说明原因。
- **推荐**:方法保持聚焦,避免超过三层嵌套;优先使用卫语句、提取方法或清晰的布尔变量。
- **必须**:避免魔法值、重复代码、过深嵌套和无业务价值的抽象。
- **必须**:不要提交仅由全局换行、import 重排或格式化导致的无关 diff。
## 导入
- **必须**:禁止通配符导入。
- **推荐**:按静态导入、Java/Jakarta 标准库、第三方库、项目内部包分组,组间空一行。
- **推荐**:同组内按字典序排列;若项目格式化器定义了不同顺序,以格式化器为准。
- **必须**:删除未使用导入,不通过全限定类名规避正常导入。
## 注释与 Javadoc
- **必须**:公共 API、接口抽象方法和不显然的契约说明使用 Javadoc,包含参数约束、返回语义和可观察异常。
- **必须**:修改逻辑时同步更新相关注释;陈旧注释视为缺陷。
- **必须**:注释说明意图、业务原因、约束或权衡,不复述语句表面含义。
- **必须**:枚举字段或代码值必须能看出业务含义,可通过 Javadoc、构造参数或明确命名表达。
- **推荐**TODO/FIXME 包含可追踪的任务标识和原因;若无跟踪机制则完成或删除。
- **必须**:不要保留大段注释掉的代码,版本历史可承担恢复职责。
- **必须**:所有新增类必须有 Javadoc,首句说明职责而非复述类名。
- **必须**:类 Javadoc 使用作者 `xiang`,通过 `@since` 记录实际首次创建日期,日期格式固定为 `yyyy-MM-dd`;后续修改不得覆盖首次创建日期。
- **推荐**:对复杂业务逻辑解释“为什么”和特殊规则,不逐行翻译代码;业务分支意图不明显时补充说明。
- **必须**:禁止保留 `yourname``TODO author` 等占位内容。
Javadoc 采用以下格式;`yyyy-MM-dd` 必须替换为实际首次创建日期,不得原样保留:
```java
/**
* 类的职责说明
*
* @author xiang
* @since yyyy-MM-dd
*/
```
@@ -0,0 +1,49 @@
# 类型、OOP 与 API 设计
## 类型与相等性
- **必须**:包装类型使用 `equals``Objects.equals` 比较值,不使用 `==`;警惕缓存范围造成的偶然相等。
- **必须**`BigDecimal` 使用字符串或精确来源构造;数值大小用 `compareTo`,需要比较值与 scale 时才用 `equals`
- **必须**:货币、比例和计量值明确精度、舍入方式与单位;禁止用 `double` 承载精确金额。
- **必须**:重写 `equals` 时同时重写 `hashCode`,并验证对称性、传递性和集合行为。
- **推荐**:用领域类型、枚举和受约束构造器替代多个语义不明的 `String``int` 参数。
- **必须**:类型转换前检查范围和语义;不得以强制转换静默截断数值。
## 空值与返回值
- **必须**:明确参数与返回值的 nullability;不得依靠调用方猜测。
- **推荐**:返回空集合或空数组而非 `null`;不要为避免判断而创建语义虚假的空领域对象。
- **推荐**`Optional` 主要用于可能缺失的返回值;不要默认用于实体字段、DTO 字段、方法参数或集合元素。
- **必须**:禁止无条件链式解引用可能为空的对象;在边界校验或使用清晰分支表达缺失语义。
- **必须**:不要用断言校验外部输入,因为生产环境可能禁用断言。
- **推荐**:在系统边界尽早校验参数;项目支持 Bean Validation 时优先使用 `@Valid``@NotNull``@NotBlank``@Size` 等声明式校验。
- **推荐**:内部前置条件优先复用项目已有校验工具;只有需要定制业务错误码或分支处理时才手写空值判断。
- **必须**:不得仅为判空新增依赖。
- **推荐**:项目没有现成判空工具时,对象使用 `obj == null`,集合使用 `collection == null || collection.isEmpty()`Map 使用 `map == null || map.isEmpty()`;只有项目已经依赖 Apache Commons Collections 时,才使用 `CollectionUtils.isEmpty()``MapUtils.isEmpty()`
## OOP 与封装
- **必须**:遵循单一职责和最小可见性;字段默认 `private`,只暴露必要 API。
- **必须**:构造完成后对象应满足不变量;不要暴露可变内部集合、数组或日期对象。
- **推荐**:优先组合而非继承;继承只用于稳定的 is-a 关系和可替换契约。
- **必须**:覆写方法使用 `@Override`;可变参数只用于同类型、同语义参数,不使用 `Object...` 逃避类型设计。
- **必须**:构造器不得启动线程、访问远程资源或发布未完全构造的 `this`
- **推荐**:不可变对象优先;必要时使用 defensive copy,并确保集合元素也符合可变性预期。
- **推荐**:接口保持内聚,不创建囊括无关操作的“大而全” Service 或 Util。
## API 与兼容性
- **必须**:公共 API 明确输入校验、返回语义、错误模型、幂等性和副作用。
- **必须**:新增重载时检查 `null`、lambda、自动装箱和可变参数是否造成调用歧义。
- **必须**:修改 DTO、枚举、JSON 字段、RPC 签名或异常类型前评估调用方兼容性。
- **推荐**:返回接口类型而非具体集合实现;不要泄漏 ORM 实体、框架上下文或内部异常。
- **推荐**:避免布尔参数控制多个行为,优先使用有语义的方法、枚举或选项对象。
- **必须**:不得以反射、原始类型或未检查转换绕过编译器,除非边界隔离、理由明确并有测试。
## Lombok
- **必须**:仅在项目已采用 Lombok 时使用,不为风格统一单独引入依赖。
- **参考**DTO/VO 可使用 `@Data`;使用前检查可变性、相等性和敏感字段,存在特殊约束时改用明确的 `@Getter``@Setter``@EqualsAndHashCode``@ToString`
- **推荐**:实体类和值对象避免使用 `@Data`;按项目约定组合 `@Getter``@Setter``@Builder``@NoArgsConstructor``@AllArgsConstructor`,且不得绕过领域不变量或 ORM 构造约束。
- **推荐**:除非继承关系确有需要,不设置 `@EqualsAndHashCode(callSuper = true)`
- **必须**`toString` 不得暴露敏感字段,也不得触发懒加载或递归引用。
@@ -0,0 +1,34 @@
# 集合、并发与时间
## 集合
- **必须**:选择与语义相符的集合;需要唯一性用 `Set`,需要键查找用 `Map`,不要靠线性扫描模拟索引。
- **推荐**:规模可预估时设置合理初始容量,但不得按不可信输入直接分配超大容器。
- **必须**`Arrays.asList` 不是可增删列表;数组元素变化会反映到视图。需要独立可变列表时显式复制。
- **必须**:集合转数组使用类型安全的 `toArray` 形式,并遵循项目 JDK 的惯用写法。
- **必须**:遍历时删除元素应使用迭代器、`removeIf` 或收集后处理,不在增强 `for` 中直接结构性修改。
- **必须**:不要修改 `Map.keySet()``values()` 等视图后假设原映射不变。
- **必须**:自定义对象作为 `Map` 键或 `Set` 元素时保证 `equals/hashCode` 稳定;插入后不得改变参与哈希的字段。
- **推荐**:返回只读视图或副本时明确其快照/联动语义;`unmodifiable` 不等于深度不可变。
- **推荐**:Stream 用于清晰的数据变换;有副作用、异常流程或复杂分支时使用普通循环。
## 并发
- **必须**:先识别共享可变状态,再选择不可变、线程封闭、并发容器、原子类或锁;`volatile` 不能保证复合操作原子性。
- **必须**:线程池必须有清晰的线程数、队列、线程命名、拒绝策略和关闭策略。传统平台线程池不得直接使用默认无界的便捷工厂掩盖这些参数。
- **参考**:Java 21+ 虚拟线程需确认项目支持、阻塞模型、限流方式与 `ThreadLocal` 成本;不要把虚拟线程当作无限资源。
- **必须**`ThreadLocal` 使用后在 `finally` 中清理,尤其在线程池和请求复用场景。
- **必须**:锁范围尽可能小,不在持锁期间执行未知回调、远程调用或慢 I/O;多个锁必须有固定顺序。
- **必须**:捕获 `InterruptedException` 后恢复中断标记或明确终止流程,不得吞掉中断。
- **推荐**:高并发随机数使用 `ThreadLocalRandom`;共享计数根据竞争程度选择原子类或累加器。
- **推荐**:并行 Stream 仅在数据量、无副作用、线程池影响和基准数据明确时使用。
- **必须**:并发正确性不能只靠一次测试;检查竞态、可见性、重复执行、超时、取消与关闭路径。
## 日期与时间
- **必须**:优先使用 `java.time`;旧 `Date/Calendar` 仅用于兼容边界并尽快转换。
- **必须**:业务时间明确时区。存储时间点优先用 `Instant`,面向地区规则时显式使用 `ZoneId`
- **必须**:不得共享非线程安全的旧式日期格式化器;优先使用不可变的 `DateTimeFormatter`
- **必须**:持续时间测量使用单调时钟语义,如 `System.nanoTime()`;不要用墙上时钟计算短耗时。
- **必须**:时间测试固定 `Clock` 或等价抽象,避免依赖当前时间造成不稳定测试。
- **推荐**:日期边界、夏令时、闰年和跨时区转换要有针对性用例。
@@ -0,0 +1,46 @@
# 异常、日志与安全
## 异常
- **必须**:异常表达失败语义,不用异常控制正常分支。
- **必须**:不要直接抛出宽泛的 `Exception``RuntimeException``Throwable`;使用标准的精确异常或稳定的领域异常。
- **必须**:不得空 `catch`、只打印堆栈或吞掉异常。转换异常时保留 cause,并补充不含敏感数据的上下文。
- **必须**:同一层通常选择“处理并记录”或“向上抛出”,避免每层重复记录同一异常。
- **必须**:可通过前置检查避免的错误应先校验;并发竞态场景仍以原子操作结果为准。
- **必须**:资源使用 try-with-resources`finally` 不得用 `return` 覆盖原返回值或异常。
- **必须**:捕获范围保持最小,不用一个大 `try` 模糊具体失败点。
- **推荐**:对外错误模型稳定、可追踪且不泄漏内部栈、SQL、文件路径或依赖细节。
## 日志
- **必须**:使用项目日志门面,不使用 `System.out``System.err``printStackTrace`
- **必须**:参数化记录日志,不做无必要的字符串拼接;异常对象作为日志框架支持的异常参数传入。
- **必须**:日志级别符合可操作性:预期业务拒绝通常不是 error,系统不可恢复失败不能只写 debug。
- **必须**:禁止记录密码、令牌、密钥、完整证件号、银行卡、Cookie、会话或未脱敏请求体。
- **推荐**:记录稳定的事件、结果、耗时、非敏感标识和 trace/correlation id;避免在高频循环中刷屏。
- **必须**:日志不得改变业务行为;日志表达式不得触发远程调用、延迟加载或明显昂贵计算。
- **推荐**:项目同时使用 SLF4J 和 Lombok 时采用 `@Slf4j`,否则遵循项目统一的日志门面与声明方式。
- **必须**`error` 仅用于由当前层最终处理、需要人工介入的系统失败,并包含异常堆栈和已脱敏的定位上下文。
- **推荐**`warn` 用于异常但可恢复、仍需要关注的状态。
- **推荐**:预期业务拒绝通常使用 `info` 或不记录,避免制造告警噪声。
- **必须**:同一异常只在负责最终处理的层记录一次;转换异常时保留原始 cause,不在中间层重复打印堆栈。
## 输入与权限
- **必须**:所有外部输入在信任边界验证类型、长度、范围、格式、集合规模和允许值;前端校验不能替代服务端校验。
- **必须**:认证后仍要做功能级和对象级授权,不能只检查“是否登录”。
- **必须**:SQL 使用参数绑定;排序字段、表名、列名等不可绑定的元数据必须采用服务端白名单。
- **必须**:输出到 HTML、脚本、URL、日志或命令时按目标上下文编码;不要自行拼接转义规则。
- **必须**:状态变更接口按框架能力启用 CSRF、防重放、幂等或频控措施。
- **必须**:文件路径规范化并限制在允许根目录;URL 请求限制协议、主机、重定向和内网地址以防 SSRF。
- **必须**:禁止反序列化不可信 Java 原生对象流;JSON 多态、表达式、脚本和正则能力采用最小白名单。
- **必须**:凭据来自受控配置或密钥服务,不写入源码、测试、日志和错误响应。
- **推荐**:使用成熟安全库和框架默认防护,不自行实现密码学、会话、签名或随机令牌算法。
## 事务与一致性
- **必须**:事务边界与业务原子性一致,避免在长事务中执行远程调用或不可控 I/O。
- **必须**:明确异常类型是否触发回滚;框架代理、自调用和异步边界可能使事务注解失效。
- **必须**:事务方法捕获异常后必须重新抛出、显式标记回滚或完成可靠补偿。
- **必须**:重试仅用于可重试失败,并要求操作幂等、退避、次数上限和可观测性。
- **推荐**:跨系统一致性采用项目既有 outbox、事件或补偿机制,不临时发明“先写库再发消息”的脆弱流程。
@@ -0,0 +1,38 @@
# 工程分层与数据访问
## 分层与依赖
- **必须**:遵循项目既有模块边界和依赖方向;领域层不得反向依赖 Web、ORM 或具体基础设施实现。
- **必须**Controller/Endpoint 负责协议适配与边界校验,不承载核心业务编排。
- **必须**:持久化对象、领域对象和 API DTO 的转换边界明确;不得把 ORM 实体直接作为外部契约。
- **推荐**:使用构造器注入表达必需依赖并支持测试;字段注入仅在项目框架约束明确时使用。
- **推荐**:工具类无状态、职责单一且构造器不可见;不要创建混杂业务逻辑的通用 `Utils`
- **必须**:循环依赖表示边界问题,不以延迟注入作为默认解决方案。
## 数据访问
- **必须**:禁止字符串拼接用户输入生成 SQL;MyBatis 默认使用 `#{}``${}` 只允许经过严格白名单的元数据。
- **必须**:明确查询列,不使用 `SELECT *` 作为生产查询默认写法。
- **必须**:分页总数为零时避免继续执行无意义的数据查询;限制最大页大小和排序字段。
- **必须**:批量查询、写入和 `IN` 参数有明确上限并按数据库能力分批。
- **必须**:避免循环中逐条远程或数据库调用;检查 N+1 查询和不受控懒加载。
- **必须**:更新语句只更新预期字段;乐观锁、版本号或条件更新必须检查受影响行数。
- **必须**:事务内查询和更新基于明确隔离假设;不能用应用层 `if` 代替数据库唯一约束或原子条件。
- **推荐**:索引设计与真实查询条件、排序和基数一致;新增查询必须评估执行计划或沿用已验证索引。
- **推荐**:数据库约束与应用校验共同保护核心不变量,不机械套用“禁止所有外键”;服从项目的数据治理策略。
## Spring、Jakarta 与 ORM
- **必须**Bean Validation 放在真实入口并确保级联校验生效;内部调用仍需保护领域不变量。
- **必须**`@Transactional`、缓存、异步和权限注解必须考虑代理边界、自调用、方法可见性和异常回滚语义。
- **必须**JPA 实体的 `equals/hashCode` 不得依赖会变化的数据库生成标识造成集合异常。
- **推荐**:默认避免 Open Session in View 带来的隐式查询;在服务边界显式获取所需数据。
- **必须**MyBatis/JPA 映射字段、枚举、时区和 null 语义必须有测试,不能仅凭同名假设自动映射正确。
## 构建与依赖
- **必须**:新增或升级依赖前确认项目 BOM、dependency management、版本锁定和许可证/安全要求。
- **必须**:生产发布不依赖不可复现的 SNAPSHOT 或动态版本,除非项目流程明确批准。
- **必须**:依赖变更检查传递依赖、冲突、打包体积和运行时兼容;不要只确认“能编译”。
- **推荐**:优先使用 JDK 与项目已有库;为一个简单方法引入大型依赖通常不合理。
- **必须**:生成代码和资源遵循构建目录约定,不手改会被生成器覆盖的文件。
@@ -0,0 +1,67 @@
# 测试、审查与验证
## 测试设计
- **必须**:测试代码放在项目约定的测试源集,通常为 `src/test/java`;不得把测试逻辑混入生产代码。
- **必须**:每个测试具有清晰的 Arrange/Act/Assert 或 Given/When/Then 结构,一个失败能指出一个主要行为。
- **必须**:测试独立、可重复、可并行时不互相污染;不得依赖执行顺序、真实当前时间、随机外网或共享生产数据。
- **必须**:断言业务结果、状态变化和外部交互,不只断言“无异常”或覆盖实现细节。
- **推荐**:遵循 AIR 原则:Automatic、Independent、Repeatable;覆盖 BCDEBoundary、Correct、Design、Error。
- **必须**:缺陷修复先加入能复现问题的测试;新行为先建立失败证据,再实现通过。
- **推荐**:单元测试隔离自身职责,集成测试验证真实框架映射、事务、序列化和数据库行为。
- **必须**:Mock 只隔离边界,不复刻被测实现;过多 Mock 通常提示职责或测试层级错误。
- **推荐**:测试命名表达条件与预期,服从项目现有 JUnit/TestNG、Mockito、AssertJ 等风格。
## 风险用例
按任务选择至少检查:
- null、空值、最小/最大长度、零、负数、溢出、重复和非法枚举;
- 精度、舍入、字符编码、Locale、时区和夏令时;
- 超时、重试、重复请求、部分失败、事务回滚和幂等;
- 并发更新、锁竞争、中断、资源关闭和线程池拒绝;
- 未认证、未授权、越权、注入、恶意大输入和敏感信息泄漏;
- 序列化前后兼容、数据库映射和旧调用方行为。
## Code Review 清单
1. 将每条需求映射到实现与至少一项验证证据。
2. 阅读完整 diff 和必要上下文,不只看新增行。
3. 检查是否覆盖用户已有改动或包含无关格式化。
4. 检查空值、异常、资源、并发、事务、数据规模和安全边界。
5. 检查 API、DTO、SQL、配置与依赖的兼容性。
6. 检查测试能在错误实现下失败,避免只验证 Mock 自己的返回。
7. 将发现按 `阻断/严重/一般/建议` 分级,并给出触发条件和影响。
8. 修复后重新阅读 diff 并重跑受影响验证。
## 命令选择
先从仓库文档和 CI 获取标准命令,常见候选仅供识别:
```text
Maven: ./mvnw test
Gradle: ./gradlew test
```
不要假定包装器、模块名或 profile 一定存在。优先运行:
1. 单个受影响测试;
2. 受影响模块测试;
3. 编译与项目配置的 formatter/Checkstyle/PMD/SpotBugs
4. 风险要求的集成测试或全量构建。
项目已配置 P3C 时使用既有入口。若未配置,进行人工规则 Review,并把“未运行 P3C”明确写为未验证项,而不是临时修改构建。
## 结果报告
每项验证记录:
```text
命令或检查:
范围:
结果:通过 / 失败 / 未执行
证据摘要:
失败或未执行原因:
```
只报告本次实际获得的证据。环境错误、既有失败和本次回归必须区分;无法确定归属时标记为待调查,不得猜测。