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

279 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Java后端开发规范
> 拟稿:[黎润豪](/lirh)<a href="https://blog.lroyia.top" target="_blank">(个人博客)</a>
>
> <div><span>版本号 1.0.0 </span></div>
>
## 目录
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Java后端开发规范](#java%E5%90%8E%E7%AB%AF%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83)
- [前言](#%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)
- [代码结构](#%E4%BB%A3%E7%A0%81%E7%BB%93%E6%9E%84)
- [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)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## 前言
本文为公司Java后端开发的代码规范规范分如下两级
- ![强制](../img/icon/强制.png) :开发者必须遵循的开发规范要求
- ![推荐](../img/icon/推荐.png) :开发者选择性遵循的开发规范要求
原则约定至上Keep Simple。周志尧指定
约定优于配置。
## 编程约束
### 命名风格
- ![强制](../img/icon/强制.png) 代码中的命名不能以下划线或美元符号开始,也不能以下划线或美元符号结束。
- ![强制](../img/icon/强制.png) 杜绝完全不规范的缩写,避免望文不知义。
> ![反例](../img/icon/反例.png) AbstractClass缩写成AbsClasscondition缩写成condiFunction缩写成Fu。
- ![强制](../img/icon/强制.png) 严禁使用非全世界都知道的拼音命名。
> ![正例](../img/icon/正例.png) alibaba/youku/hangzhou
> ![反例](../img/icon/反例.png) suanFen【算分】getGTHTypeCode【获取个体户类型编码】
#### 类命名
- ![强制](../img/icon/强制.png) 采用大驼峰UpperCamelCase命名法禁止使用数字命名。
> ![正例](../img/icon/正例.png) KeyPairGlobalConfig
> ![反例](../img/icon/反例.png) areaSliceAreaSlice1AreaSlice2
- ![推荐](../img/icon/推荐.png) 采用【名词】,【形容词+名词】的格式进行命名
> ![正例](../img/icon/正例.png) SMSSenderGlobalConfig
> ![反例](../img/icon/反例.png) SendSMS
- ![强制](../img/icon/强制.png) 抽象类必须以Abstract或Base开头工具类例外如StringUtils异常类名明必须以Exception结尾测试类必须以Test结尾。
- ![强制](../img/icon/强制.png) 接口的参数类必须要以VO或Dto结尾命名接口与接口之间的传输参数传输类必须以Dto结尾命名。
#### 方法命名
- ![强制](../img/icon/强制.png) 采用小驼峰LowerCamelCase命名法禁止使用拼音命名
- ![推荐](../img/icon/推荐.png) 方法参数不多于5个多于5个后改用DTO进行传输。
#### 变量命名
- ![强制](../img/icon/强制.png) 常量与枚举均使用大写+下划线组合的方式命名
> ![正例](../img/icon/正例.png) LIMIT_SIZEENTITY_TYPE
- ![强制](../img/icon/强制.png) 采用小驼峰LowerCamelCase命名法禁止使用拼音命名
- ![强制](../img/icon/强制.png) 局部非循环与下标变量不可使用单字母命名特殊数学含义例外如斜截式的斜率a常数b
### 泛型
- ![强制](../img/icon/强制.png) 涉及泛型的类,严禁不写前泛。
![正例](../img/icon/正例.png)
```java
List<String> resultList = new ArrayLisy<>();
```
![反例](../img/icon/反例.png)
```java
List resultList = new ArrayLisy<String>();
Map resultList = new HashMap();
```
### 代码结构
- ![强制](../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) 数据查询命名规则
a)获取单个对象的方法用`get`作前缀
b)获取多个对象的方法用`list`作前缀
c)获取统计值的方法用`count`作前缀
d)插入的方法用`save`作前缀
e)删除的方法用`remove`作前缀
f)修改的方法用`modify/update`作前缀
### Dao/Mapper层
- ![推荐](../img/icon/推荐.png) 数据查询命名规则
a)获取单个对象的方法用`select`作前缀
b)获取多个对象的方法用`select`作前缀`List`作后续`selectXxxList`。
c)获取统计值的方法用`count`作前缀
d)插入的方法用`insert`作前缀
e)删除的方法用`delete`作前缀
f)修改的方法用`update`作前缀
## 接口管理规范
- ![强制](../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. 后端编码不要捕获任何异常
不要在业务代码中编写捕获异常的代码, daoservicecontroller 层的所有的异常都全部抛出到上层
业务代码中只处理正确的功能, 不对异常做任何判断,后端切忌通过异常类型或者异常出现与否来决定业务逻辑
2. 后端统一处理异常
业务代码中不捕获异常, 系统所有异常都会抛出到 Controller 系统基础框架会统一拦截由日志框架记录异常栈的信息并统一返回标准的结果信息RestResult
3. 前端统一处理
前端组件对后端返回结果集进行统一处理对不同类型的异常进行相应业务逻辑的处理
- ![强制](../img/icon/强制.png) 方法若有显式的RuntimeException异常抛出必须使用`throws`关键字将其标识到方法上
- ![强制](../img/icon/强制.png) 异常的打印均用日志对象的error等级输出
- ![强制](../img/icon/强制.png) IDEA发现的空指针问题必须要处理掉
- ![强制](../img/icon/强制.png) 捕获异常和跑异常必须完全匹配或者捕获异常是抛异常的父类
- ![强制](../img/icon/强制.png) 若异常被捕获如果数据需要回滚一定要注意进行手动回滚
## 日志规约
- ![强制](../img/icon/强制.png) 日志对象在项目引用了lombok的情况下请用@SLF4J注解声明
- ![强制](../img/icon/强制.png) 所有日志文件至少保存15天
- ![强制](../img/icon/强制.png) 日志信息拼接使用`{}`占位符以提高可读性和拼接性能
- ![强制](../img/icon/强制.png) 生产环境进制直接使用`System.out``System.err``e.printStackTrace()`充当日志输出
- ![强制](../img/icon/强制.png) 避免重复打印日志浪费磁盘空间务必在日志配置文件中的子logger配置additivity=false
```xml
<logger name="com.chinaweal.dao" level="debug" additivity="false"/>
```
## 工程结构
- ![强制](../img/icon/强制.png) 包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语词。包名统一使用单数形式,但是类名如果有复数含义,类名可以使用复数形式。
- ![正例](../img/icon/正例.png):用工具类包名为`com.alibaba.ai.util`、类名为`MessageUtils`
- ![推荐](../img/icon/推荐.png) 目录结构com.chinaweal.{项目简称}.{通用配置名/数据源缩写}.{业务板块名}.{controller/service/entity/mapper}