贴一份我之前整理的 JAVA开发规范:
JAVA开发规范
代码整体风格
- Controller类,不要直接使用Map,HttpServletRequest request,HttpServletResponse response 作为参数,不要使用 Servlet API的接口
- 一个service类不应该引用其他service类,但是可以引用多个dao层对象
- mapper类应该尽量轻量级,不要过多的自定义sql
- 使用BeanUtil,而不是setXxx(info.getXxx)
- 避免重复代码,代码段出现过3次,一定要提取更多的公共代码到基础层, 比如mint
- 方法不超过200行,一个类不超过1000
- 看到丑陋代码, 重构它!时不时 重构!
- 使用设计模式!
- 代码要 提高 复用, 但是不能复制,复制一时爽,但是并不能提高 复用性!~
- 对自己做的模块负责, 对其业务逻辑要一清二楚! 否则就 不合格~@!
- 面向对象编程,更重要的是 面向接口
- 同一个含义的枚举, 全局应该只出现一次,而不是每个模块一次, 否则改起来还是很麻烦!避免枚举类泛滥
- 不要动不动就mq,避免消息泛滥
- 不超过3层 if else
- 专业术语的 英文名字要统一,简写也要统一
- 一般情况下,方法签名不要抛出异常,除非涉及资源的工具类 !
- 不应该使用 硬编码
- 提高 内聚, 降低耦合! 不要一个Service就一个方法, 不要引用太多其他的Service, 分得太散了就会 导致 太松散,内聚性太差! 看代码,调试都会很痛苦!
- 杜绝代码坏味道!啰嗦 / 低级 / 重复代码, 一概拒绝!
- 能够提取的, 一定要提取到公共位置, 杜绝 复制黏贴, 杜绝丑陋代码!
- 代码保持简单,灵活,复用性,独立,高内聚,低耦合
- 每个方法要 逻辑十分清晰, 一目了然
- 代码应该清晰可读,尽量保持简单易读
- 统一的code style
- 不要为了 微服务而 微服务 !
大家使用统一的规范,方便交流,减少维护成本
服务分层、命名规范
服务名\服务名-api\src\main\java\com\wisdom\服务名\
service 所有的服务接口,统一前缀为I,后缀为 Service
子模块名x
IXxxService
子模块名y
IXxxService
IMainXxx1Service 不要出现 XxxParam、 XxxSearch
IMainXxx2Service
IMainXxx3Service
bank other service
dto 所有的前后端交互对象,统一后缀为 DTO
exception 所有的自定义异常,应该继承于运行时异常,统一后缀为Exception
服务名\服务名-provider\src\main\java\com\wisdom\服务名\
common 所有全局的共享东西:所有的常量、枚举、静态类,包括各种工具类,redis、mq访问工具类
Constants 当前服务共用的常量类
XxxUtil 当前服务共用的工具类
XxxBaseService 当前服务共用的服务类
XxxRedisUtil 当前服务共用的redis工具类
XxxRabbitMqUtil 当前服务共用的mq工具类
XxxConfig 示例:com.wisdom.jasmine.mvc.CheckLoginInterceptor
XxxHandler 示例:com.wisdom.jasmine.mvc.GlobalExceptionHandler
XxxException 特有的异常类
service 处理业务逻辑,所有的服务接口实现类,统一后缀为 ServiceImpl,如有必要,下面还可以创建一层package,表明子模块名,但是package不宜太深
子模块名x
XxxServiceImpl
子模块名y
YyyServiceImpl
MainXxx1ServiceImpl
MainXxx2ServiceImpl
MainXxx3ServiceImpl
mapper 所有的数据库访问类,统一后缀为Mapper
XxxMapper
YyyMapper 只有复杂的 查询sql, 不应该有修改、新增、删除sql
model 所有的数据库实体映射类,统一后缀为Model
XxxModel
YyyModel
message 后端和mq 交互的pojo,尽量少使用,应该使用DTO
Web层就是controller层,直接前端对接项目,服务名一定要有一个 web 后缀
服务名\服务名-web\src\main\java\com\wisdom\服务名\
controller 处理视图,所有的Controller类,统一后缀为 Controller
XxxController
api 服务的dto,provider服务的model 应该不相同,否则考虑是否服务没定义 / 划分好。
每个表对应一个model,一个mapper。但不需要每一个model 一个service,比如一些关联表的查询/新增/修改/删除操作,直接在主表对于的service完成。
每个service应该有对应的一个主表。但有时候也可能有多个。
一般情况下,service和mapper和model和数据库表 同名。
XxxParam、 XxxSearch、XxxMessage 不能忘文知义,增加沟通成本,而且转换起来很麻烦。
为什么Service层不能调用其它Service?
比较清晰的单向关联:
N向关联(可能存在循环依赖):
一般命名规范
Controller层 |
Service层 |
DAO层 |
|
query/page |
getOne |
selectOne |
获取单个实体,参数就是实体本身 |
getByYyy |
selectById |
按照ID获取单个实体 |
|
list Page
|
selectByXxx |
按照某条件获取单个实体,参数就是实体某个字段 |
|
|
按照某条件,获取实体的list集合 |
||
listAll |
selectAll |
返回所有行 |
|
add |
add |
insert |
新增单个实体。不存在 insertByXxx 方法 |
modify |
modify |
update |
更新单个实体 |
updateByXxx |
这个情况少见, 一般是通过id 进行更新 |
||
save |
save |
|
新增或修改, 不需要saveOrUpdate 方法名 |
业务方法 |
相同 业务方法 |
相同或不需要 |
|
Service 层:
list获取实体的list集合
page 分页查询,统一返回, PageInfo<实体Model>
数据流转:
数据库层命名规范
字段使用要统一, state、status、 统一 status
表: 表的业务含义应该清晰明确, 不宜使用过多字段。< 30 ..
princ inter
不要这样引起误会的缩写,
要么就不使用缩写,而是全写,要么使用通用的缩写,
pom 规范
pom 提取公共配置 commons
使用最少的dependency,尽量从parent中继承
依赖应该尽量简化
需要仔细考虑每一个dependency 是否是必须的
注释规范
每个类写明 用途、注释、作者、关联
每次修改 写明原因、作者、时间
/**
* 这个类是为了做什么,主要用途是abc
*
* @author LK(lk@qq.com)
* @Time 2018-12-29
*/
javadoc 注释标签语法
@author 对类的说明 标明开发该类模块的作者
@version 对类的说明 标明该类模块的版本
@see 对类、属性、方法的说明 参考转向,也就是相关主题
@param 对方法的说明 对方法中某参数的说明
@return 对方法的说明 对方法返回值的说明
@exception 对方法的说明 对方法可能抛出的异常进行说明
日志规范
理解和使用 debug、info、warn、error 各个级别,一般日志使用info基本,捕捉到错误如果要记录异常,必须使用 error 级别。
异常处理规范
- Controller 做主要的参数检验,空指针检查。不做具体的异常处理, 异常处理统一到MVC的ExceptionHandler
- Service层捕捉所有的已知异常(受检异常),对系统异常封装返回,对业务异常返回错误码和错误信息,空指针检查。(处理已知异常,运行时异常不用管)
- dao/mapper 不捕捉异常
尽量不要try catch(Exception e) 这个由统一的MVC的ExceptionHandler 来做
不合理的示例
mapper.AttachmentMapper#deleteAttachmentByObject 方法是不是可以简化为 delete ?
mapper.AttachmentMapper#queryByObject queryByObject -> query
provider.RepayOverdueProvider#insertOrUpdateCommit 奇怪的命名
provider.CreditorAdvanceProvider provider 是什么? service 还是Dao?
lock.LockKeys lock 一个package 只有一个类, 是不是放到 constants 更好?
invite.enums.QueryDateTypeEnum enums 是不是放到 constants 更好?
invite.utils.ActivityInviteUtil 不需要单独建立util 包
product.utils.UploadUtils UploadUtils 并不是 product 才有的一个工具类
product.service.impl.ProductServiceImpl provider 服务 使用service 还是 service.impl ? 至少应该是统一
domain.custom.CollectionCalendarView
search.CreditorAdvanceSearch
com.wisdom.daffodil.model.bank.BindCardReq 不要搞特殊化,统一使用DTO就好
阿里巴巴规范
【强制】POJO 类中布尔类型的变量,都不要加 is ,否则部分框架解析会引起序列化错误。
【强制】不要使用一个常量类维护所有常量,应该按常量功能进行归类,分开维护
【强制】所有的覆写方法,必须加@ Override 注解。
【强制】所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较。
【强制】关于基本数据类型与包装数据类型的使用标准如下:
1 ) 所有的 POJO 类属性必须使用包装数据类型。
2 ) RPC 方法的返回值和参数必须使用包装数据类型。
3 ) 所有的局部变量【推荐】使用基本数据类型。
【强制】定义 DO / DTO / VO 等 POJO 类时,不要设定任何属性默认值。
【强制】 POJO 类必须写 toString 方法。使用 IDE 的中工具: source > generate ,toString时,如果继承了另一个 POJO 类,注意在前面加一下 super.toString 。
【强制】关于 hashCode 和 equals 的处理,遵循如下规则:
1) 只要重写 equals ,就必须重写 hashCode 。
2) 因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的对象必须重写这两个方法。
3) 如果自定义对象做为 Map 的键,那么必须重写 hashCode 和 equals 。
【强制】 ArrayList 的 subList 结果不可强转成 ArrayList , 否则会抛出 ClassCastException异常: java . util . RandomAccessSubList cannot be cast to java . util . ArrayList ;
【强制】 在 subList 场景中,高度注意对原集合元素个数的修改,会导致子列表的遍历、增加、删除均产生 ConcurrentModificationException 异常。
【强制】使用工具类 Arrays . asList() 把数组转换成集合时,不能使用其修改集合相关的方法,它的 add / remove / clear 方法会抛出UnsupportedOperationException 异常。
【强制】线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。
【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
【强制】 SimpleDateFormat 是线程不安全的类,一般不要定义为 static 变量,如果定义为
static ,必须加锁,或者使用 DateUtils 工具类。
【强制】对多个资源、数据库表、对象同时加锁时,需要保持一致的加锁顺序,否则可能会造成死锁。
【强制】多线程并行处理定时任务时, Timer 运行多个 TimeTask 时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用 ScheduledExecutorService 则没有这个问题。
【强制】在一个 switch 块内,每个 case 要么通过 break / return 等来终止,要么注释说明程序将继续执行到哪一个 case 为止 ; 在一个 switch 块内,都必须包含一个 default 语句并且放在最后,即使它什么代码也没有。
【强制】不要捕获 Java 类库中定义的继承自 RuntimeException 的运行时异常类,如:
IndexOutOfBoundsException / NullPointerException,这类异常由程序员预检查
来规避,保证程序健壮性。
【强制】异常不要用来做流程控制,条件控制,因为异常的处理效率比条件分支低。
【强制】对大段代码进行try-catch,这是不负责任的表现。catch时请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码。对于非稳定代码的catch尽可能进行区分异常类型,再做对应的异常处理。
【强制】捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容。
【参考】在代码中使用“抛异常”还是“返回错误码”,对于公司外的http/api开放接口必须使用“错误码”;而应用内部推荐异常抛出;跨应用间RPC调用优先考虑使用Result方式,封装isSuccess()方法、“错误码”、“错误简短信息”。
文件是:
https://files.cnblogs.com/files/FlyAway2013/2018-JAVA%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83.rar