# 阿里巴巴Java开发手册 - Cursor规则

本项目遵循《阿里巴巴Java开发手册（黄山版）》的编码规范。以下规则将指导AI助手在编写、审查和重构Java代码时的行为。

## 一、编程规约

### 命名风格

- **类名**：使用 UpperCamelCase 风格（如：UserService, OrderDTO）
- **方法名、参数名、变量名**：使用 lowerCamelCase 风格（如：getUserInfo, userName）
- **常量名**：全部大写，单词间用下划线隔开（如：MAX_STOCK_COUNT）
- **抽象类**：使用 Abstract 或 Base 开头
- **异常类**：使用 Exception 结尾
- **测试类**：以要测试的类名开始，以 Test 结尾
- **数组定义**：类型与中括号紧挨相连（如：int[] arrayDemo）
- **包名**：统一使用小写，点分隔符之间有且仅有一个自然语义的英语单词
- **禁止**：命名不能以下划线或美元符号开始/结束；禁止使用拼音与英文混合；禁止使用中文命名
- **禁止**：代码和注释中避免使用种族歧视性或侮辱性词语

### 常量定义

- **禁止魔法值**：不允许任何未经预先定义的常量直接出现在代码中
- **Long类型**：数值后使用大写 L（如：2L），不能是小写 l
- **浮点数**：数值后缀统一为大写的 D 或 F（如：175.5D, 150.3F）
- **常量分类**：按功能归类，分开维护，不要使用一个常量类维护所有常量

### 代码格式

- **缩进**：采用 4 个空格缩进，禁止使用 Tab 字符
- **大括号**：左大括号前不换行，左大括号后换行；右大括号前换行
- **单行字符数**：限制不超过 120 个，超出需要换行
- **方法行数**：单个方法的总行数不超过 80 行
- **空行**：不同逻辑、不同语义、不同业务的代码之间插入一个空行

### OOP规约

- **静态访问**：避免通过对象引用访问静态变量或静态方法，直接用类名访问
- **覆写方法**：所有的覆写方法，必须加 @Override 注解
- **可变参数**：相同参数类型、相同业务含义才可使用可变参数，参数类型避免定义为 Object
- **equals方法**：使用常量或确定有值的对象来调用 equals，避免空指针异常
- **整型包装类**：所有整型包装类对象之间值的比较，全部使用 equals 方法比较
- **浮点数比较**：基本数据类型不能使用 == 进行比较，包装数据类型不能使用 equals 进行判断
- **BigDecimal**：等值比较应使用 compareTo() 方法，而不是 equals() 方法
- **POJO类**：属性必须使用包装数据类型；必须写 toString 方法；不要设定任何属性默认值
- **构造方法**：禁止加入任何业务逻辑，如果有初始化逻辑，请放在 init 方法中

### 集合处理

- **hashCode和equals**：只要覆写 equals，就必须覆写 hashCode
- **集合判空**：使用 isEmpty() 方法，而不是 size() == 0
- **Stream toMap**：使用 toMap() 方法时，必须使用 mergeFunction 参数处理重复 key
- **foreach循环**：不要在 foreach 循环里进行元素的 remove/add 操作，使用 iterator 方式
- **集合转数组**：必须使用集合的 toArray(T[] array)，传入类型完全一致、长度为 0 的空数组

### 并发处理

- **单例对象**：获取单例对象需要保证线程安全，其中的方法也要保证线程安全
- **线程池**：线程资源必须通过线程池提供，不允许在应用中自行显式创建线程
- **线程池创建**：不允许使用 Executors 去创建，而是通过 ThreadPoolExecutor 的方式
- **SimpleDateFormat**：是线程不安全的类，一般不要定义为 static 变量
- **ThreadLocal**：必须回收自定义的 ThreadLocal 变量记录的当前线程的值
- **锁的使用**：能用无锁数据结构就不要用锁；能锁区块就不要锁整个方法体；能用对象锁就不要用类锁
- **死锁预防**：对多个资源、数据库表、对象同时加锁时，需要保持一致的加锁顺序

## 二、异常日志

### 错误码

- **错误码格式**：字符串类型，共 5 位，分成两个部分：错误产生来源 + 四位数字编号
- **错误来源**：A 表示用户端错误，B 表示系统执行出错，C 表示调用第三方服务出错
- **全部正常**：返回五个零：00000
- **禁止**：错误码不能直接输出给用户作为提示信息使用

### 异常处理

- **RuntimeException**：可以通过预检查方式规避的 RuntimeException 不应该通过 catch 来处理
- **异常控制流**：异常捕获后不要用来做流程控制、条件控制
- **异常分类**：catch 时请分清稳定代码和非稳定代码，尽可能进行区分异常类型
- **异常处理**：捕获异常是为了处理它，不要捕获了却什么都不处理而抛弃之
- **事务回滚**：事务场景中，抛出异常被 catch 后，如果需要回滚，一定要注意手动回滚事务
- **资源关闭**：finally 块必须对资源对象、流对象进行关闭，有异常也要做 try-catch
- **finally return**：不要在 finally 块中使用 return
- **异常匹配**：捕获异常与抛异常，必须是完全匹配，或者捕获异常是抛异常的父类
- **RPC异常**：在调用 RPC、二方包、或动态生成类的相关方法时，捕捉异常使用 Throwable 类进行拦截

### 日志规约

- **日志框架**：应用中不可直接使用日志系统（Log4j、Logback）中的 API，而应依赖使用日志框架（SLF4J、JCL）中的 API
- **日志保存**：日志文件至少保存 15 天
- **日志拼接**：字符串变量之间的拼接使用占位符的方式
- **日志级别判断**：对于 trace/debug/info 级别的日志输出，必须进行日志级别的开关判断
- **禁止**：生产环境禁止使用 System.out 或 System.err 输出或使用 e.printStackTrace() 打印异常堆栈
- **异常信息**：异常信息应该包括两类信息：案发现场信息和异常堆栈信息

## 三、单元测试

- **AIR原则**：好的单元测试必须遵守 AIR 原则（Automatic、Independent、Repeatable）
- **自动化执行**：单元测试应该是全自动执行的，并且非交互式的
- **独立性**：保持单元测试的独立性，单元测试用例之间决不能互相调用
- **可重复执行**：单元测试是可以重复执行的，不能受到外界环境的影响
- **测试粒度**：要保证测试粒度足够小，有助于精确定位问题，单测粒度至多是类级别，一般是方法级别
- **测试目录**：单元测试代码必须写在 src/test/java，不允许写在业务代码目录下

## 四、安全规约

- **权限控制**：隶属于用户个人的页面或者功能必须进行权限控制校验
- **数据脱敏**：用户敏感数据禁止直接展示，必须对展示数据进行脱敏
- **SQL注入**：用户输入的 SQL 参数严格使用参数绑定或者 METADATA 字段值限定，防止 SQL 注入，禁止字符串拼接 SQL
- **参数验证**：用户请求传入的任何参数必须做有效性验证
- **XSS防护**：禁止向 HTML 页面输出未经安全过滤或未正确转义的用户数据
- **CSRF防护**：表单、AJAX 提交必须执行 CSRF 安全验证
- **URL重定向**：URL 外部重定向传入的目标地址必须执行白名单过滤
- **防重放**：使用平台资源（短信、邮件、电话、下单、支付）必须实现正确的防重放的机制
- **文件上传**：对于文件上传功能，需要对于文件大小、类型进行严格检查和控制
- **密码加密**：配置文件中的密码需要加密

## 五、MySQL数据库

### 建表规约

- **布尔字段**：表达是与否概念的字段，必须使用 is_xxx 的方式命名，数据类型是 unsigned tinyint
- **表名字段名**：必须使用小写字母或数字，禁止出现数字开头，禁止两个下划线中间只出现数字
- **表名**：不使用复数名词
- **保留字**：禁用保留字，如 desc、range、match、delayed 等
- **索引命名**：主键索引名为 pk_字段名；唯一索引名为 uk_字段名；普通索引名则为 idx_字段名
- **小数类型**：为 decimal，禁止使用 float 和 double
- **必备字段**：表必备三字段：id，create_time，update_time
- **逻辑删除**：在数据库中不能使用物理删除操作，要使用逻辑删除

### 索引规约

- **唯一索引**：业务上具有唯一特性的字段，即使是组合字段，也必须建成唯一索引
- **JOIN限制**：超过三个表禁止 join
- **索引长度**：在 varchar 字段上建立索引时，必须指定索引长度
- **模糊查询**：页面搜索严禁左模糊或者全模糊，如果需要请走搜索引擎来解决

### SQL语句

- **count使用**：不要使用 count(列名) 或 count(常量) 来替代 count(*)
- **NULL判断**：使用 ISNULL() 来判断是否为 NULL 值
- **外键级联**：不得使用外键与级联，一切外键概念必须在应用层解决
- **存储过程**：禁止使用存储过程
- **表别名**：对于数据库中表记录的查询和变更，只要涉及多个表，都需要在列名前加表的别名进行限定

### ORM映射

- **字段列表**：在表查询中，一律不要使用 * 作为查询的字段列表，需要哪些字段必须明确写明
- **布尔属性映射**：POJO 类的布尔属性不能加 is，而数据库字段必须加 is_，要求在 resultMap 中进行字段与属性之间的映射
- **resultMap**：不要用 resultClass 当返回参数，即使所有类属性名与数据库字段一一对应，也需要定义 resultMap
- **参数绑定**：sql.xml 配置参数使用：#{}，#param# 不要使用 ${} 此种方式容易出现 SQL 注入
- **更新时间**：更新数据表记录时，必须同时更新记录对应的 update_time 字段值为当前时间

## 六、工程结构

### 应用分层

- **分层结构**：开放 API 层、终端显示层、Web 层、Service 层、Manager 层、DAO 层、第三方服务、外部数据接口
- **领域模型**：
  - DO（Data Object）：与数据库表结构一一对应
  - DTO（Data Transfer Object）：数据传输对象
  - BO（Business Object）：业务对象
  - Query：数据查询对象
  - VO（View Object）：显示层对象

### 二方库依赖

- **GAV规则**：定义 GAV 遵从 com.{公司/BU}.业务线.[子业务线] 格式
- **版本号**：主版本号.次版本号.修订号，注意起始版本号必须为：1.0.0
- **SNAPSHOT**：线上应用不要依赖 SNAPSHOT 版本（安全包除外）

## 七、设计规约

- **存储方案**：存储方案和底层数据结构的设计获得评审一致通过，并沉淀成为文档
- **用例图**：如果与系统交互的 User 超过一类并且相关的 UseCase 超过 5 个，使用用例图来表达
- **状态图**：如果某个业务对象的状态超过 3 个，使用状态图来表达
- **时序图**：如果系统中某个功能的调用链路上的涉及对象超过 3 个，使用时序图来表达
- **类图**：如果系统中模型类超过 5 个，且存在复杂的依赖关系，使用类图来表达
- **弱依赖**：系统设计时要准确识别出弱依赖，并针对性地设计降级和应急预案
- **单一原则**：类在设计与实现时要符合单一原则
- **继承谨慎**：谨慎使用继承的方式来进行扩展，优先使用聚合/组合的方式来实现
- **依赖倒置**：根据依赖倒置原则，尽量依赖抽象类与接口，有利于扩展与维护

## 使用说明

当编写、审查或重构Java代码时，请严格遵循以上规则。这些规则基于《阿里巴巴Java开发手册（黄山版）》，是Java社区集体智慧的结晶。

**规约分类说明：**
- **【强制】**：必须严格遵守，违反可能导致严重问题
- **【推荐】**：建议遵循，有助于提升代码质量
- **参考**：参考性建议，可根据实际情况选择

**版本信息：**
- 版本：黄山版（1.7.1）
- 更新日期：2022.02.03
