JAVA开发规范v1.0
一、编程规约
(一)命名风格
1. 【强制】代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。
反例:_name / __name / $Object / name_ / name$ / Object$
2. 【强制】代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。
说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义。
正例:mioodo / taobao / youku / hangzhou 等国际通用的名称,可视同英文。
反例:youjiaoProduct[幼教] / getPingfenByName() [评分] / int 某变量 = 3
3. 【强制】类名使用 UpperCamelCase 风格,必须遵从驼峰形式,但以下情形例外:DO / BO / DTO / VO / AO
正例:MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion
反例:macroPolo / UserDo / XMLService / TCPUDPDeal / TAPromotion
4. 【强制】方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从驼峰形式。
正例: localValue / getHttpMessage() / inputUserId
5. 【强制】常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。
正例:MAX_STOCK_COUNT
反例:MAX_COUNT
6. 【强制】抽象类命名使用 Abstract 或 Base 开头;异常类命名使用 Exception 结尾;测试类命名以它要测试的类的名称开始,以 Test 结尾。
7. 【强制】包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用单数形式,但是类名如果有复数含义,类名可以使用复数形式。
正例: 应用工具类包名为 com.mioodo.util、类名为 MessageUtils(此规则参考spring 的框架结构)
8. 【推荐】为了达到代码自解释的目标,任何自定义编程元素在命名时,使用尽量完整的单词组合来表达其意。
正例:从远程仓库拉取代码的类命名为 PullCodeFromRemoteRepository。
反例:变量 int a; 的随意命名方式。
9.接口和实现类的命名有两套规则:
1)【强制】对于 Service 和 DAO 类,基于 SOA 的理念,暴露出来的服务一定是接口,内部的实现类用 Impl 的后缀与接口区别。
正例:CacheServiceImpl 实现 CacheService 接口。
2)【推荐】如果是形容能力的接口名称,取对应的形容词做接口名(通常是–able 的形式)。
正例:AbstractTranslator 实现 Translatable。
10.【参考】枚举类名建议带上 Enum 后缀,枚举成员名称需要全大写,单词间用下划线隔开。
说明:枚举其实就是特殊的常量类,且构造方法被默认强制是私有。
正例:枚举名字为 ProcessStatusEnum 的成员名称:SUCCESS / UNKOWN_REASON。
11.【强制】各层命名规约:
A) Service/DAO 层方法命名规约
1) 获取单个对象的方法用 get 做前缀。
2) 获取多个对象的方法用 list 做前缀。
3) 获取统计值的方法用 count 做前缀。
4) 插入的方法用 save 做前缀。
5) 删除的方法用delete 做前缀。
6) 修改的方法用 update 做前缀。
B) 领域模型命名规约
1) 数据对象:xxx,xxx 即为数据表名。
2) 数据传输对象:入参:C2Sxxx、返回:S2Cxxx,xxx 为业务领域相关的名称。
3) POJO 是 DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO。
(二)代码格式
1.【强制】每个自定义方法体最多不超过100行代码,除try...catch...外最少不能少于3行代码。
2.【强制】单行字符数限制不超过 120 个,超出需要换行,换行时遵循如下原则:
1) 第二行相对第一行缩进 4 个空格,从第三行开始,不再继续缩进,参考示例。
2) 运算符与下文一起换行。
3) 方法调用的点符号与下文一起换行。
4) 方法调用时,多个参数,需要换行时,在逗号后进行。
5) 在括号前不要换行,见反例。
正例:
StringBuffer sb = new StringBuffer();
// 超过 120 个字符的情况下,换行缩进 4 个空格,点号和方法名称一起换行
sb.append("zi").append("xin")...
.append("huang")...
.append("huang")...
.append("huang");
反例:
StringBuffer sb = new StringBuffer();
// 超过 120 个字符的情况下,不要在括号前换行
sb.append("zi").append("xin")...append
("huang");
// 参数很多的方法调用可能超过 120 个字符,不要在逗号前换行
method(args1, args2, args3, ... , argsX);
3.【强制】方法参数在定义和传入时,多个参数逗号后边必须加空格。
正例:下例中实参的"a",后边必须要有一个空格。
method("a", "b", "c");
4.【强制】IDE 的 text file encoding 设置为 UTF-8; IDE 中文件的换行符使用 Unix 格式,
不要使用 Windows 格式。
(三)注释规约
1. 【强制】类、类属性、类方法的必须添加注释,使用 Javadoc 规范,使用/**内容*/格式,不得使用// xxx 方式。
说明:在 IDE 编辑窗口中,Javadoc 方式会提示相关注释,生成 Javadoc 可以正确输出相应注释;在 IDE 中,工程调用方法时,不进入方法即可悬浮提示方法、参数、返回值的意义,提高阅读效率。
2. 【强制】接口必须要用 Javadoc 注释、除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能。
说明:对子类的实现要求,或者调用注意事项,请一并说明。
3. 【强制】所有的类都必须添加创建者和创建日期。
4. 【强制】方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释使用/* */注释,注意与代码对齐。
5.【强制】所有的枚举类型字段、常量必须要有注释,说明每个数据项的用途。
6.【强制】所有Controller层的接口都必须添加swaggerui相关注解,并把接口名称、描述、参数名、返回参数描述清楚。
示例:@Api(tags = "Controller业务描述")
@ApiOperation(value = "功能描述", tags = "Controller业务描述")
(五)类与接口
1.基本原则
类的划分粒度,不可太大,造成过于庞大的单个类,也不可太细,从而使类的继承太深。般而言。
多使用设计模式,便于重构。
多个类中使用相同方法时将其方法提到一个接口中或使用抽象类,尽量提高重用度。将不希望再被继承的类声明成final,例如某些实用类,但不要滥用fial,否则会对系统的可扩展性造成影响。
将不希望被实例化的类的缺省构造方法声明成private。
2.抽象类与接口
一般而言:接口定义行为,而抽象类定义属性和公有行为,注意两者间的取舍,在设计中,可由接口定义公用的行为,由一个抽象类来实现其部分或全部方法,以给子类提供统一的行为定义,可参考Java集合等实现。
多使用接口,尽量做到面向接口的设计,以提高系统的可扩展性。
3.继承与组合
尽量使用组合来代替继承,一则可以使类的层次不至于过深,而且会使类与类,包与包之间的耦合度更小,更具可扩展性。
4.构造函数和静态工厂方法
当需要使用多个构造函数创建类时,建议使用静态工厂方法替代这些构造方法。
(六)方法
1.基本原则
一个方法只完成一项功能,在定义系统的公用接口方法外的方法应尽可能的缩小其可见性。避免用一个类是实例去访问其静态变量和方法。避免在一个较长的方法里提供多个出口。
2.参数和返回值
避免过多的参数列表,尽量控制在5个以内,若需要传递多个参数时,当使用一个容纳这些参数的对象进行传递,以提高程序的可读性和可扩展性,
参数类型和返回值尽量接口化,以屏蔽具体的实现细节,提高系统的可打扩展性。
(七)开放接口访问约定
1. 【强制】对外开发接口必须通过API管理平台进行管理和配置
2. 【强制】对外开放接口统一采用post方式,且参数必须添加私钥加密参数sign,加密参数中包含普通参数、时间戳、网关层统一拦截处理
3. 【强制】对外开放的接口和rpc调用的接口需要进行参数校验
(八)异常处理
- 【强制】异常不要用来做流程控制,条件控制,因为异常的处理效率比条件分支低。
- 【强制】对大段代码进行 try-catch,这是不负责任的表现。catch 时请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码。对于非稳定代码的 catch 尽可能进行区分异常类型,再做对应的异常处理。
- 【强制】捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容。
- 【强制】有 try 块放到了事务代码中,catch 异常后,如果需要回滚事务,一定要注意手动回滚事务。
- 【强制】finally 块必须对资源对象、流对象进行关闭,有异常也要做 try-catch。
- 【强制】不能在 finally 块中使用 return,finally 块中的 return 返回后方法结束执行,不会再执行 try 块中的 return 语句。
- 【强制】避免直接抛出 new RuntimeException(), 更不允许抛出 Exception 或者 Throwable,应使用有业务含义的自定义异常。推荐业界已定义过的自定义异常,如:ServiceException 等。 在业务逻辑内部抛出ServiceException,Controller层必须catchException,并返回
try {
cartDTO.setAppCode(this.getCurrentAppCode());
cartDTO.setOrgCode(this.getCurrentOrgCode());
cartService.save(cartDTO);
return RestApiResponse.ok();
}catch (ServiceException e){
logger.info(“加入购物车操作异常:”+e.getMessage());
return RestApiResponse.error(e,"加入购物车失败");
}
(九)返回码规约
1.【强制】对于公司对外开放的http/api 开放接口必须使用“错误码”;而应用内部推荐异常抛出;跨应用间 RPC 调用使用 ApiResponse 方式,封装返回码、错误描述信息。
2.【强制】应答返回码的成功为200,应答异常返回为500,
网关服务异常返回502,业务异常返回501
通用返回码:40101 token解析错误
40102 token已过期
40331 没有接口的访问权限
41001 api的秘钥不存在
41002调用接口的IP地址不在白名单中,请在接口IP白名单中进行设置。
41003 调用次数超出限制
41004 请求超出时效
41005 参数校验失败
41006 请求方式不正确
42000 响应超时
43001 服务不可用
常见细节问题整理
1.所有的feign远程调用服务接口统一返回RestApiResponse,且调用服务方必须判断服务返回状态
2、所有的FeignClient必须配置fallback方法
3、getCurrentAppCode返回的为ruian_app或ruian_pc,查询和保存数据统一修改为使用getCurrentDataAppCode()
4、如果有接口需要区分新旧版本,可以使用getCurrentAppVersion获取版本号来处理
5、save/update/delete 在controller层必须处理异常,不允许直接返回null作为判断依据
6、不允许使用selectByExample查询列表数据,只能根据id或did查询单条数据,后续selectByExample会逐步替换掉
7、业务处理逻辑不要写到controller
8、多表更新操作需要加上本地事务。
(十)测试与Bug跟踪
1.基本原则
测试不通过的代码不得提交到git库或者发布。
不得隐瞒、忽略、绕过任何Bug,有Bug不一定是你的错,但有了Bug不作为就是你的不对了。
多做测试,测试要完全,尽量将各种可能情况都测试通过,尽量将可能的Bug在开发中捕捉并处理掉。
测试时应当对数据库等资源不留或少留痕迹,例如,当测试添加一个用户时,在其成功后当及时从数据库中除该记录,以避免脏数据的产生。
对关键功能必须测试并通过,对辅助功能及非常简单之功能可不做测试。
2. Postman单元测试
在Java应用中,开发的功能要使用Postman工具进行单元测试。
3. Bug跟踪和缺陷处理
当系统出现Bug时当由该Bug的负责人(代码负责人)尽快修改之
Bug的处理根据其优先级高低和级别高低先后处理。
禁止隐瞒Bug。