diff --git a/img/Exception.jpg b/img/Exception.jpg new file mode 100644 index 0000000..4a62000 Binary files /dev/null and b/img/Exception.jpg differ diff --git a/img/Exception1.jpg b/img/Exception1.jpg new file mode 100644 index 0000000..e6c3513 Binary files /dev/null and b/img/Exception1.jpg differ diff --git a/技术规范/Java后端开发规范.md b/技术规范/Java后端开发规范.md index 5385632..b54f4e9 100644 --- a/技术规范/Java后端开发规范.md +++ b/技术规范/Java后端开发规范.md @@ -10,18 +10,29 @@ - [Java后端开发规范](#java%E5%90%8E%E7%AB%AF%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83) - - [目录](#%E7%9B%AE%E5%BD%95) - - [前言](#%E5%89%8D%E8%A8%80) - - [编程约束](#%E7%BC%96%E7%A8%8B%E7%BA%A6%E6%9D%9F) - - [命名](#%E5%91%BD%E5%90%8D) - - [类命名](#%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) - - [异常处理](#%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86) - - [日志规约](#%E6%97%A5%E5%BF%97%E8%A7%84%E7%BA%A6) + +- [前言](#%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) - - [工程结构](#%E5%B7%A5%E7%A8%8B%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) @@ -32,9 +43,14 @@ - ![强制](../img/icon/强制.png) :开发者必须遵循的开发规范要求 - ![推荐](../img/icon/推荐.png) :开发者选择性遵循的开发规范要求 +原则:约定至上;Keep Simple。(周志尧指定) +约定优于配置。 + ## 编程约束 -### 命名 +### 命名风格 + +- ![强制](../img/icon/强制.png) 代码中的命名不能以下划线或美元符号开始,也不能以下划线或美元符号结束。 - ![强制](../img/icon/强制.png) 杜绝完全不规范的缩写,避免望文不知义。 @@ -94,7 +110,138 @@ List resultList = new ArrayLisy(); 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. 后端编码不要捕获任何异常 +不要在业务代码中编写捕获异常的代码, 即 dao、service、controller 层的所有的异常都全部抛出到上层; +业务代码中只处理正确的功能, 不对异常做任何判断,后端切忌通过异常类型、或者异常出现与否来决定业务逻辑; +2. 后端统一处理异常 +业务代码中不捕获异常, 系统所有异常都会抛出到 Controller 层,系统基础框架会统一拦截,由日志框架记录异常栈的信息,并统一返回标准的结果信息RestResult; +3. 前端统一处理 +前端组件对后端返回结果集进行统一处理,对不同类型的异常进行相应业务逻辑的处理; - ![强制](../img/icon/强制.png) 方法若有显式的RuntimeException异常抛出,必须使用`throws`关键字将其标识到方法上 @@ -122,10 +269,10 @@ Map resultList = new HashMap(); ``` -## 代码结构 - -- ![推荐](../img/icon/推荐.png) `{}`代码块嵌套不应超过4层 - ## 工程结构 +- ![强制](../img/icon/强制.png) 包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语词。包名统一使用单数形式,但是类名如果有复数含义,类名可以使用复数形式。 + +- ![正例](../img/icon/正例.png):用工具类包名为`com.alibaba.ai.util`、类名为`MessageUtils` + - ![推荐](../img/icon/推荐.png) 目录结构com.chinaweal.{项目简称}.{通用配置名/数据源缩写}.{业务板块名}.{controller/service/entity/mapper}