public/技术规范/Java后端开发规范.md

279 lines
15 KiB
Markdown
Raw Normal View History

2021-12-20 16:30:26 +08:00
# Java后端开发规范
> 拟稿:[黎润豪](/lirh)<a href="https://blog.lroyia.top" target="_blank">(个人博客)</a>
>
2021-12-22 11:04:24 +08:00
> <div><span>版本号 1.0.0 </span></div>
2021-12-20 16:30:26 +08:00
>
2021-12-22 14:59:08 +08:00
2021-12-22 14:59:51 +08:00
## 目录
2021-12-24 17:27:25 +08:00
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
2021-12-22 14:59:08 +08:00
- [Java后端开发规范](#java%E5%90%8E%E7%AB%AF%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83)
2021-12-28 15:20:47 +08:00
- [前言](#%E5%89%8D%E8%A8%80)
- [编程约束](#%E7%BC%96%E7%A8%8B%E7%BA%A6%E6%9D%9F)
- [命名风格](#%E5%91%BD%E5%90%8D%E9%A3%8E%E6%A0%BC)
- [类命名](#%E7%B1%BB%E5%91%BD%E5%90%8D)
- [方法命名](#%E6%96%B9%E6%B3%95%E5%91%BD%E5%90%8D)
- [变量命名](#%E5%8F%98%E9%87%8F%E5%91%BD%E5%90%8D)
- [泛型](#%E6%B3%9B%E5%9E%8B)
2021-12-22 14:59:08 +08:00
- [代码结构](#%E4%BB%A3%E7%A0%81%E7%BB%93%E6%9E%84)
2021-12-28 15:20:47 +08:00
- [OOP规约](#oop%E8%A7%84%E7%BA%A6)
- [控制语句](#%E6%8E%A7%E5%88%B6%E8%AF%AD%E5%8F%A5)
- [注释规范](#%E6%B3%A8%E9%87%8A%E8%A7%84%E8%8C%83)
- [系统分层规范](#%E7%B3%BB%E7%BB%9F%E5%88%86%E5%B1%82%E8%A7%84%E8%8C%83)
- [controller层](#controller%E5%B1%82)
- [service层](#service%E5%B1%82)
- [Dao/Mapper层](#daomapper%E5%B1%82)
- [接口管理规范](#%E6%8E%A5%E5%8F%A3%E7%AE%A1%E7%90%86%E8%A7%84%E8%8C%83)
- [异常处理规范](#%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E8%A7%84%E8%8C%83)
- [异常处理](#%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86)
- [异常处理原则](#%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E5%8E%9F%E5%88%99)
- [异常处理的编码规范](#%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E7%9A%84%E7%BC%96%E7%A0%81%E8%A7%84%E8%8C%83)
- [日志规约](#%E6%97%A5%E5%BF%97%E8%A7%84%E7%BA%A6)
- [工程结构](#%E5%B7%A5%E7%A8%8B%E7%BB%93%E6%9E%84)
2021-12-22 14:59:08 +08:00
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
2021-12-24 17:27:25 +08:00
2021-12-20 16:30:26 +08:00
## 前言
本文为公司Java后端开发的代码规范规范分如下两级
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) :开发者必须遵循的开发规范要求
- ![推荐](../img/icon/推荐.png) :开发者选择性遵循的开发规范要求
2021-12-20 16:30:26 +08:00
2021-12-28 15:20:47 +08:00
原则约定至上Keep Simple。周志尧指定
约定优于配置。
2021-12-20 16:30:26 +08:00
## 编程约束
2021-12-28 15:20:47 +08:00
### 命名风格
- ![强制](../img/icon/强制.png) 代码中的命名不能以下划线或美元符号开始,也不能以下划线或美元符号结束。
2021-12-20 16:30:26 +08:00
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 杜绝完全不规范的缩写,避免望文不知义。
2021-12-20 16:30:26 +08:00
2021-12-22 11:36:05 +08:00
> ![反例](../img/icon/反例.png) AbstractClass缩写成AbsClasscondition缩写成condiFunction缩写成Fu。
2021-12-20 16:30:26 +08:00
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 严禁使用非全世界都知道的拼音命名。
2021-12-20 16:30:26 +08:00
2021-12-22 11:36:05 +08:00
> ![正例](../img/icon/正例.png) alibaba/youku/hangzhou
> ![反例](../img/icon/反例.png) suanFen【算分】getGTHTypeCode【获取个体户类型编码】
2021-12-20 16:30:26 +08:00
#### 类命名
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 采用大驼峰UpperCamelCase命名法禁止使用数字命名。
2021-12-20 16:30:26 +08:00
2021-12-22 11:36:05 +08:00
> ![正例](../img/icon/正例.png) KeyPairGlobalConfig
> ![反例](../img/icon/反例.png) areaSliceAreaSlice1AreaSlice2
2021-12-20 16:30:26 +08:00
2021-12-22 11:36:05 +08:00
- ![推荐](../img/icon/推荐.png) 采用【名词】,【形容词+名词】的格式进行命名
2021-12-20 16:30:26 +08:00
2021-12-22 11:36:05 +08:00
> ![正例](../img/icon/正例.png) SMSSenderGlobalConfig
> ![反例](../img/icon/反例.png) SendSMS
2021-12-20 16:30:26 +08:00
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 抽象类必须以Abstract或Base开头工具类例外如StringUtils异常类名明必须以Exception结尾测试类必须以Test结尾。
2021-12-20 16:30:26 +08:00
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 接口的参数类必须要以VO或Dto结尾命名接口与接口之间的传输参数传输类必须以Dto结尾命名。
2021-12-20 16:30:26 +08:00
#### 方法命名
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 采用小驼峰LowerCamelCase命名法禁止使用拼音命名
2021-12-20 16:30:26 +08:00
2021-12-22 11:36:05 +08:00
- ![推荐](../img/icon/推荐.png) 方法参数不多于5个多于5个后改用DTO进行传输。
2021-12-20 16:30:26 +08:00
2021-12-21 17:29:15 +08:00
#### 变量命名
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 常量与枚举均使用大写+下划线组合的方式命名
2021-12-21 17:29:15 +08:00
2021-12-22 11:36:05 +08:00
> ![正例](../img/icon/正例.png) LIMIT_SIZEENTITY_TYPE
2021-12-21 17:29:15 +08:00
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 采用小驼峰LowerCamelCase命名法禁止使用拼音命名
2021-12-21 17:29:15 +08:00
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 局部非循环与下标变量不可使用单字母命名特殊数学含义例外如斜截式的斜率a常数b
2021-12-21 17:29:15 +08:00
2021-12-24 17:13:50 +08:00
### 泛型
2021-12-24 17:10:24 +08:00
- ![强制](../img/icon/强制.png) 涉及泛型的类,严禁不写前泛。
2021-12-24 17:13:50 +08:00
![正例](../img/icon/正例.png)
```java
List<String> resultList = new ArrayLisy<>();
```
![反例](../img/icon/反例.png)
```java
List resultList = new ArrayLisy<String>();
Map resultList = new HashMap();
```
2021-12-24 17:10:24 +08:00
2021-12-28 15:20:47 +08:00
### 代码结构
- ![强制](../img/icon/强制.png) 采用 4 个空格缩进,禁止使用 tab 字符。IDEA 设置 tab 为 4 个空格时,请勿勾选 `Use tab character`;(设置界面 `editor -> code style -> java`
- ![强制](../img/icon/强制.png) 单行字符数限制不超过120个超出需要换行; (设置界面 `File -> Settings -> Code Sytle` 中勾选`Wrap on typing`选项,`Right Margin`为设置的字符数限制)
- ![推荐](../img/icon/推荐.png) `{}`代码块嵌套不应超过4层
- ![推荐](../img/icon/推荐.png) 单个方法的总行数不超过 100 行。
> 说明:除注释之外的方法签名、左右大括号、方法内代码、空行、回车及任何不可见字符的总行数不超过 100行。代码逻辑分清红花和绿叶个性和共性绿叶逻辑单独出来成为额外方法使主干代码更加清晰共性逻辑抽取成为共性方法便于复用和维护。
### OOP规约
- ![强制](../img/icon/强制.png) 构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,放在 init 方法中。
- ![推荐](../img/icon/推荐.png) 当一个类有多个构造方法,或者多个同名方法,这些方法应该按顺序放置在一起,便于阅读。
- ![推荐](../img/icon/推荐.png) 类内方法定义的顺序依次是:公有方法或保护方法 > 私有方法 > getter / setter 方法。
> 说明:公有方法是类的调用者和维护者最关心的方法,首屏展示最好;保护方法虽然只是子类关心,也可能是“模板设计模式”下的核心方法;而私有方法外部一般不需要特别关心,是一个黑盒实现;因为承载的信息价值较低,所有 Service 和 DAO 的 getter/setter 方法放在类体最后。
- ![推荐](../img/icon/推荐.png) `setter`方法中,参数名称与类成员变量名称一致,`this.成员名 = 参数名`。在`getter/setter`方法中,不要增加业务逻辑,增加排查问题的难度。
- ![推荐](../img/icon/推荐.png) 循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。
> 说明:下例中,反编译出的字节码文件显示每次循环都会 new 出一个 StringBuilder 对象,然后进行 append 操作,最后通过 toString 方法返回 String 对象,造成内存资源浪费。
### 控制语句
- ![推荐](../img/icon/推荐.png) 除常用方法(如`getXxx/isXxx`)等外,不要在条件判断中执行其它复杂的语句,将复杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性。
> 说明:很多 if 语句内的逻辑表达式相当复杂,与、或、取反混合运算,甚至各种方法纵深调用,理解成 本非常高。如果赋值一个非常好理解的布尔变量名字,则是件令人赏心悦目的事情。
- ![推荐](../img/icon/推荐.png) 不要在其它表达式(尤其是条件表达式)中,插入赋值语句。
> 说明:赋值点类似于人体的穴位,对于代码的理解至关重要,所以赋值语句需要清晰地单独成为一行。
- ![推荐](../img/icon/推荐.png) 循环体中的语句要考量性能,以下操作尽量移至循环体外处理,如定义对象、变 量、获取数据库连接,进行不必要的`try - catch`操作(这个`try - catch`是否可以移至循环体外)。
### 注释规范
- ![强制](../img/icon/强制.png) 类、类属性、类方法的注释必须使用 Javadoc 规范,使用/*内容/格式,不得使用 // xxx 方式。
> 说明:在 IDE 编辑窗口中Javadoc 方式会提示相关注释,生成 Javadoc 可以正确输出相应注释;在 IDE 中,工程调用方法时,不进入方法即可悬浮提示方法、参数、返回值的意义,提高阅读效率。
- ![强制](../img/icon/强制.png) 所有的抽象方法 包括接口中的方法 必须要用 Javadoc 注释、除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能。
- ![强制](../img/icon/强制.png) 所有的类都必须添加创建者和创建日期。
- ![强制](../img/icon/强制.png) 方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释 使用/**/注释,注意与代码对齐。
- ![强制](../img/icon/强制.png) 所有的枚举类型字段必须要有注释,说明每个数据项的用途。
- ![推荐](../img/icon/推荐.png) 代码修改的同时,注释也要进行相应的修改,尤其是参数、返回值、异常、核心逻辑等的修改。
- ![推荐](../img/icon/推荐.png) 谨慎注释掉代码。在上方详细说明,而不是简单地注释掉。如果无用,则删除。
- ![推荐](../img/icon/推荐.png) 对于注释的要求:第一、能够准确反映设计思想和代码逻辑 第二、能够描述业务含义,使别的程序员能够迅速了解到代码背后的信息。完全没有注释的大段代码对于阅读者形同天书,注释是给自己看的,即使隔很长时间,也能清晰理解当时的思路 注释也是给继任者看的,使其能够快速接替自己的工作。
- ![推荐](../img/icon/推荐.png) 好的命名、代码结构是自解释的,注释力求精简准确、表达到位。
## 系统分层规范
### controller层
- ![强制](../img/icon/强制.png) 仅接收参数和拼凑返回数据,不写具体的业务逻辑, 所有业务逻辑必须写到service层里。
### service层
- ![推荐](../img/icon/推荐.png) 数据查询命名规则
2021-12-28 15:24:36 +08:00
a)获取单个对象的方法用`get`作前缀。
b)获取多个对象的方法用`list`作前缀。
c)获取统计值的方法用`count`作前缀。
d)插入的方法用`save`作前缀。
e)删除的方法用`remove`作前缀。
f)修改的方法用`modify/update`作前缀。
2021-12-28 15:20:47 +08:00
### Dao/Mapper层
- ![推荐](../img/icon/推荐.png) 数据查询命名规则
2021-12-28 15:24:36 +08:00
a)获取单个对象的方法用`select`作前缀。
b)获取多个对象的方法用`select`作前缀,`List`作后续,如:`selectXxxList`。
c)获取统计值的方法用`count`作前缀。
d)插入的方法用`insert`作前缀。
e)删除的方法用`delete`作前缀。
f)修改的方法用`update`作前缀。
2021-12-28 15:20:47 +08:00
## 接口管理规范
- ![强制](../img/icon/强制.png) `controller`返回类型必须为`RestResult`。
- ![强制](../img/icon/强制.png) `controller`返回的`RestResult`必须写泛型,若泛型无法确定,请写`<?>`。
- ![推荐](../img/icon/推荐.png) 一般编码中只使用get接口只做查询不修改数据库和post修改数据库
- ![推荐](../img/icon/推荐.png) 一般编码中只使用get接口只做查询不修改数据库和post修改数据库
- ![推荐](../img/icon/推荐.png) 避免出现复杂的输入参数一般情况下不允许出现例如json字符串这样的参数这种参数可读性极差。应该定义对应的bean。
- ![强制](../img/icon/强制.png) `controller`接口的方法参数不应超过5个。如果超过则应定义相应的Bean进行传输。
## 异常处理规范
### 异常处理
异常类型主要有业务异常和应用系统异常两类:
1. 业务异常由业务编码人员在ResultCode预先定义根据业务逻辑进行设定视作正常的功能返回HTTP Status Code 200 OK
2. 业务系统异常,影响业务正常运转的异常,均视为系统功能性异常。
![Exception](../img/Exception.jpg)
### 异常处理原则
异常处理,总的原则是所有出现的异常必须要有处理;
1. 所有业务异常,前端必须要有相应的响应;
2. 所有的系统异常,后端必须要有日志记录与统一结果返回。
### 异常处理的编码规范
![Exception1](../img/Exception1.jpg)
1. 后端编码不要捕获任何异常
不要在业务代码中编写捕获异常的代码, 即 dao、service、controller 层的所有的异常都全部抛出到上层;
业务代码中只处理正确的功能, 不对异常做任何判断,后端切忌通过异常类型、或者异常出现与否来决定业务逻辑;
2. 后端统一处理异常
业务代码中不捕获异常, 系统所有异常都会抛出到 Controller 层系统基础框架会统一拦截由日志框架记录异常栈的信息并统一返回标准的结果信息RestResult
3. 前端统一处理
前端组件对后端返回结果集进行统一处理,对不同类型的异常进行相应业务逻辑的处理;
2021-12-20 16:30:26 +08:00
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 方法若有显式的RuntimeException异常抛出必须使用`throws`关键字将其标识到方法上
2021-12-21 17:29:15 +08:00
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 异常的打印均用日志对象的error等级输出
2021-12-21 17:29:15 +08:00
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) IDEA发现的空指针问题必须要处理掉
2021-12-21 17:29:15 +08:00
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 捕获异常和跑异常必须完全匹配,或者捕获异常是抛异常的父类
2021-12-21 17:29:15 +08:00
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 若异常被捕获,如果数据需要回滚,一定要注意进行手动回滚
2021-12-22 11:00:26 +08:00
## 日志规约
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 日志对象在项目引用了lombok的情况下请用@SLF4J注解声明
2021-12-22 11:00:26 +08:00
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 所有日志文件至少保存15天
2021-12-22 11:00:26 +08:00
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 日志信息拼接使用`{}`占位符,以提高可读性和拼接性能
2021-12-22 11:00:26 +08:00
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 生产环境进制直接使用`System.out``System.err`或`e.printStackTrace()`充当日志输出
2021-12-22 11:00:26 +08:00
2021-12-22 11:36:05 +08:00
- ![强制](../img/icon/强制.png) 避免重复打印日志浪费磁盘空间务必在日志配置文件中的子logger配置additivity=false
2021-12-22 11:00:26 +08:00
```xml
<logger name="com.chinaweal.dao" level="debug" additivity="false"/>
```
2021-12-28 15:20:47 +08:00
## 工程结构
2021-12-22 11:00:26 +08:00
2021-12-28 15:20:47 +08:00
- ![强制](../img/icon/强制.png) 包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语词。包名统一使用单数形式,但是类名如果有复数含义,类名可以使用复数形式。
2021-12-21 17:29:15 +08:00
2021-12-28 15:20:47 +08:00
- ![正例](../img/icon/正例.png):用工具类包名为`com.alibaba.ai.util`、类名为`MessageUtils`
2021-12-22 11:00:26 +08:00
2021-12-22 15:11:51 +08:00
- ![推荐](../img/icon/推荐.png) 目录结构com.chinaweal.{项目简称}.{通用配置名/数据源缩写}.{业务板块名}.{controller/service/entity/mapper}