# 阿里巴巴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