以下规范中未提到的,均已alibaba规范为主
1.java编码规范(包名、类名、方法名、变量名、枚举、静态常量、工具包名、微服务名)
- 1.1:包名:全部小写,多个单词新建包
- 1.2:类名:大驼峰
- 1.3:方法名:增删改查, addXxx、delXxxx、updateXxx、getOneByXxx2Xxx2Xxx、getList、、、、、
- 1.4:变量名:小驼峰,常规全局统一
- 1.5:枚举:属性名(大写,多单词下划线)、类名(XxxEnum)
- 1.6:静态变量:(大写,多单词下划线)(私有的就各自类内部定义)(公共:不同功能模块分别定义不同文件)
- 1.7:工具包名:(包名:util)(类名:XxxUtils)
- 1.8:微服务名:xxx-service
- 1.9:注释:只在service接口层增加注释,以及实现内中复杂逻辑增加注释
- 2.0:XxxxDTO XxxxVO 后缀均为大写
2.微服务项目相关模块以及包名规范
- 2.1:模块命名为xxx-service、xxx-interface
- 2.2:handler包下:
- 2.2.1:ExceptionHandler(全局异常拦截器)
- 2.2.2:MetaObjectHandler(mybatisplus自动注入)
- 2.3:config包下:
- 2.3.1:MybatisPlusConfig(mybatisplus数据库分页插件)
- 2.3.2:SwaggerConfig(swagger配置类)
- 2.4:exception包下:
- 2.4.1:ExceptionEnum(业务异常枚举)
- 2.5:feign包下:
- 2.5.1:接口命名规范为:xxx(调用方)FeignClientApi
- 2.5.2:例如:public interface AppFeignClientAPI extends AppFeignApi {}
- 2.6:interface模块:
- 2.6.1:接口命名规范为:xxx(被调用方)FeignApi
- 2.6.2:例如:public interface ProjectFeignApi {}
- 2.6.3:包名为:com.xiaoxi.xxxinterface
- 2.6.4:接口模块名为:api
- 2.6.5:例如:com.xiaoxi.xxxinterface.api.XXXFeignApi
- 2.6.6:如果interface和service出现重复DTO、VO 就copy一份
3.数据库命名规范(库名、表名、字段名、字段长度、类型)
- 3.1:库名:小写,多单词下划线隔开
- 3.2:表名:小写,多单词下划线隔开
- 3.3:字段名:小写,多单词下划线隔开
- 3.4:字段类型:性别之类以及Boolean类型——tinyint(男女/10),只有大于255长度,选用text,全局varchar
- 3.5:全局字段加上:create_time、update_time
- 3.6:字符集:utf8mb4
- 3.7:排序规则:utf8mb4_bin
- 3.8 数据库表、字段必须写注释
- 3.8 数据库表、字段必须写注释
4.返回值、接受参数、查询参数、实体类命名
- 4.1:DTO定义:
- 4.1.1:定义基础BaseDTO
- 4.1.2:各自根据业务,实现XxxxDTO、XxxxAddDTO、XxxUpdateDTO,可采用继承
- 4.2:实体类包名修改为:model,分别包含(dto、vo、entity)
- 4.3:service层,只需要抛出自定义异常即可,不需要抛出 Result.Error
- 4.4:service返回值,禁止直接返回Result,统一返回业务类,由controller接受业务类,然后进行Result返回
- 4.5:controller禁止编码业务逻辑,以及额外判断
5.传统风格接口规范
接口风格为传统get post风格,url语义化
例如
接口url
对于数据资源(数据表)
xxx代表数据库表,例如track关注表
- /xxx/add 新增
- /xxx/update 编辑
- /xxx/del 删除一个
- /xxx/get 获取一个
- /xxx/getList 所有列表
- /xxx/pagetList 分页
- /xxx/addList 批量新增
- /xxx/delList 批量删除
在初期数据表和mybatis生成器会生成固定的这些接口方法
对于业务功能(目前大多数是这个)
- /业务模块/getXXXXList 获取xxxx类型列表
- /业务模块/动词名词 业务上的通常是 动名词结合url
比如 /user/updatePhone /user/updatePwd /user/register - /业务模块/子功能
比如 /as/topcharts/game /as/topcharts/app
6.restful风格接口规范
接口风格为restful风格get、post、delete、put风格
例如
接口url
对于数据资源(数据表)
xxx代表数据库表,例如track关注表
- /xxx 新增(post,数组参数)
- /xxx/{id} 编辑(put)
- /xxx/{id} 删除一个(delete)
- /xxx/{id} 获取一个(get)
- /xxx 所有列表(get,无参)
- /xxx 分页列表(get,带分页参数)
- /xxx/{id,id,id} 批量删除(delete)
在初期数据表和mybatis生成器会生成固定的这些接口方法
对于业务功能(目前大多数是这个)
- /业务模块/XXXX 获取xxxx类型列表
- /业务模块/名词 ,通过请求方式区分请求操作
比如 /user/{id}/Phone /user/{id}/password - /业务模块/子资源
比如 /as/topcharts/game /as/topcharts/app - 登录、注册、注销接口
- 登录:/业务模块/login (post)
- 注册:/业务模块/regist (post)
- 注销:/业务模块/logout (delete)
注意:有参数都是?xxx=xxx的方式,而不是在path上直接添加 (如果是string类型,字符串里面包含/就可能出问题 避免坑),Path路径只允许携带id或者类型
7.注释规范
类注释
/**- TODO
- @version 1.0
- @author
- @date ${DATE} ${TIME}
*/
方法接口注释
**- TODO
- @author
- @date $date$ $time$
- $params$
- @return $return$
*/
8.异常和日志
- 调用外部服务等可能异常的代码块,用 try/catch 代码块捕获并在catch中记录异常跟踪日志及业务逻辑处理
- 禁止吞掉异常信息
禁止catch里不做任何记录和处理,吞掉异常及其堆栈信息
禁止: logger.error(“XXX操作异常”) 或 logger.error(“XXX操作异常”+e) 或 e.printStackTrace()
正确: logger.error(“XXX操作异常”, e)
- 对于非预期的条件,尽量增加else记录跟踪日志
- 日志记录logger需使用Slf4J代理声明,禁止绑死具体日志系统的API,避免后期更换日志组件导致代码的大量改动
private static final Logger log = LoggerFactory.getLogger(OrganizationServiceImpl.class);
如采用了lombok,可用 @Slf4j 注解替代以上声明。
- 对 trace/debug/info 级别的日志输出,必须使用占位符形式,避免直接String拼接异常信息(即使日志级别不匹配也会执行拼接操作空耗资源)。
正确写法如:
log.debug(“当前用户id: {} ,操作对象: {}=>{} “, userId, objectType, objectId);
或条件输出形式如:
if(log.isDebugEnabled()){
log.debug(“当前用户id: “+id+” ,操作对象: “+ objectType +”=> “+ objectId);
}
9.逻辑代码规范
- 接口类中的方法不需添加 public 修饰符
- 需要序列化的Bean类统一实现Serializable接口并用IDE生成serialVersionUID
public class MyEntity implements Serializable {
private static final long serialVersionUID = 123456L;
…
}
- if/else/for/while语句后必须使用大括号,即使只有一行代码。
避免NPE(NullPointException)的一些建议:
- equals比较将非空对象前置:如 “true”.equals(request.getParameter(“isXx”)),即使后者为空也不会导致NPE。
- 数据库字段可空的映射属性使用包装类型定义:如基本数据类型的int映射到数据库的null值将产生NPE,而用包装类型 Integer 则不会。
- 可能为空的变量进行必要判空,并在非预期条件下打印必要的跟踪日志,不但避免NPE,还非常便于跟踪调试。
- 级联调用 obj.getA().getB().getC() 易产生 NPE,先进行判空或使用 JDK8 的 Optional 类包装。
- 封装统一的判空类用于常用类型的判空,代码需要判空时统一调用即可。如 XX.isEmpty(), XX.isNotEmpty()
- 禁止在循环中执行耗时的操作,如在循环中执行SQL语句/调用外部服务等
// 错误的示例:
for(Long id : idList){
// 循环执行SQL查询或调用外部系统接口,产生性能问题
Entity entity = xxService.getEntityById(id);
…
}
// 此案例的更优方案是 通过idList一次性查询获取到Entity集合,然后转换为Map
- 需要保证写一致性的逻辑,在外层方法上添加事务 @Transactional(rollbackFor = Exception.class)
- 需要多次使用的可复用对象将对象单独定义,禁止多次调用取不同属性。如:
String name = userService.getUser(id).getName();
Long deptId = userService.getUser(id).getDepeId();
替换为:
User user = userService.getUser(id); String name = user.getName(), ….
10.安全规范
- 用户敏感数据禁止列表展示/导出,需要做脱敏处理,如:身份证、手机号、银行卡信息等(具体参考需求)
- 禁止写死后台管理页面的登录账号密码,为系统增加安全风险(测试阶段除外)
- 禁止代码/配置文件中出现与生产环境相关的明文密码
- 禁止侵犯他人版权,如:版权代码、版权图片、版权字体等
- 禁止数据库中存明文密码,必须加密存储
- 网络传输数据,除非使用https加密协议,否则必须进行对称加密或者非对称加密处理
11.OOP规范
- 不能使用过时的类或方法
- 所有的覆写方法,必须加@Override 注解
- 所有的 POJO 类属性必须使用包装数据类型
- RPC 方法的返回值和参数必须使用包装数据类型
- 构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在 init 方法中
- 使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全一样的数组,大小就是 list.size()
- 不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁
12.并发相关
- 线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险
- SimpleDateFormat 是线程不安全的类,一般不要定义为 static 变量,如果定义为static,必须加锁
- 线程资源必须通过线程池提供,不允许在应用中自行显式创建线程
本项目相关
- 时间撮:入参出参都是秒级
- 设备类型:AsDevice(字符串传递)
- OS版本:ASOs(字符串传递)
- 榜单类型:AsPid(字符串传递)
- 有效/无效变动:0(有效)/1(无效)