一般情况,应当尽量遵守下面各规则,特殊情况除外,如有必要需要评审! 因为约定熟成, 统一、标准的操作, 才能自动化!
一、数据库表的设计
各字段应该使用什么类型,什么精度?
- id 字段是使用 int、bigint、char还是varchar?
一般情况下建议使用 int, 而且是自动递增
int有11位,可以存储42忆数据,最大值是21亿左右,范围是-231到231-1,即 -2147483648~2147483647, 而 bigint 是 -263到263-1, 即从-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
显然 bigint 就过于庞大, 一般来说 int 也是足够,但是如果不够, 那么也可以考虑使用bigint存储。 另外, 一般情况下, 当一张表数据过千万,那么应该考虑分表分库
- 对于bool或状态字段,数据库中使用什么进行存储? int、tinyint、enum、char还是 varchar?
数据库统一 char, java统一 string, 这样可以减少出错的可能! 后端代码不做转换, 全部由前端展示的时候进行转换!!
对于bool,java中尽量不使用 enum 做展示,如果每一个bool 都给创建一个bool, 其实也是很麻烦的。我们仅仅使用静态常量表示即可。
- 日期字段需要区分是日期还是时间, 还是同时包括日期+时间,然后选择对于的数据类型:
日期字段以 _date结尾, 数据库字段的存储类型为 date
日期字段以 _time 结尾, 数据库字段的存储类型为 time
日期+时间字段以 _time 结尾, 数据库字段的存储类型为 datetime , 不应该使用 timestamp,或者long( long可读性差)
如何冗余关联字段?
比如, 某表关联的人员字段是存id 还是存name?
一般情况下,id 肯定是需要存的,name 字段则不一定, 如果需要经常做展示,那么可以使用 name 做冗余。 但是缺点是需要考虑在更新人员信息的时候,同步更新这个冗余字段。
如果不需要做展示,那么不需要冗余 name。
name 还是code?
一般情况下,name允许重复, code不允许重复,code是唯一的。所有,一般可以通过code做表关联,name做冗余展示。
字段是否需要默认值?如何设置?
所有字段都尽量设置默认值,一般情况下,数值型字段默认值为0,字符串默认'' (即空字符串)。
如果有 create_time、update_time字段,那么 create_time、update_time 应该设置为 CURRENT_TIMESTAMP, 同时update_time 应该设置为 ON UPDATE CURRENT_TIMESTAMP:
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间'
(使用数据库时间, 记得保持 数据库服务器时间和应用服务器时间同步)
字段长度
name类型字段一般不能超过25个汉字、64字符
code 由业务而定
description、remark描述字段255个汉字
排序
查询返回数据,默认按照id排序、 或者创建时间、 最后修改时间、name
通用的建表语句:
CREATE TABLE `module_business` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', `name` varchar(255) NOT NULL DEFAULT '' COMMENT 'xxx名称', -- 业务字段 `deleted` char(4) NOT NULL DEFAULT 'n' COMMENT '逻辑删除标志: 已逻辑删除: y; 正常状态: n; ', `status` char(16) NOT NULL DEFAULT 'draft' COMMENT '状态: draft 草稿;committed 已提交;audited 已审核;rejected 已驳回', `remark` varchar(255) NOT NULL DEFAULT '' COMMENT '备注', `create_by` int(11) NOT NULL DEFAULT 0 COMMENT '创建人', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_by` int(11) NOT NULL DEFAULT 0 COMMENT '最后修改人', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB COMMENT='xxx业务对象';
二、命名
通用数据库字段的命名, 下划线分隔,全部小写
主键:id 状态:status 备注:remark 创建时间:create_time 创建人:create_by 最后修改时间:update_time 最后修改人:update_by
长格式还是短格式?
比如 app_agreement表, 有人将id字段命名为agreement_id, 有人 id, 各有优缺点。这里我们强制使用id!简单明了!
对于方法名也是如此,方法命名 尽量一个动词搞定!简化! 尽量不需要方法名中添加实体对象,比如"修改":
正例:update()
反例:updateAppAgreement()
因为当前类名已经表明了是AppAgreement, 比如AppAgreementController、AppAgreementService , 当然, 这个不是强制性的,如果当前方法不是直接操作对象,跟类名没有关系,那么就还是可以在方法名后加上对象名称
通用的方法命名要统一
应该尽量统一使用通用的方法动词,而不是 奇奇怪怪的动词
新增
推荐:insert add
避免:save
删除
推荐:delete
避免:remove
修改
推荐:update
避免:setXxx modify
查单个
推荐:getById getOne
避免:select query find
列表查询:list
分页查询:page
提交:submit
审核:audit
配置:config
所有术语需要整个项目保持统一
需要保证一个单词、汉语词语在整个项目中含义一致, 不要出现不一致
名词统一:
系统: sys、system
用户: user
产品: product
订单: order
消息: msg、message
广告: ad
商品: goods
地区: area
协议、同意书: agreement
...
动词统一:
编辑: edit
配置: config
管理: manage
统计: stat
推送: push
...
名字是使用全称还是简称?
一般情况下, 常用的术语可以使用简写、缩写, 用得少的不简写(框架自带的除外)
模块命名可以简写, 表、服务、接口等命名不要简写
非常常用的地方、局部变量可以使用简写
三、项目风格
项目目录结构风格
集中还是分散?说明:
- 集中: 整个微服务只创建一个controller、一个service、一个dao、一个entity 目录, 所有的表、模块的controller都集中到一起,service/dao/entity 都依此类推
- 分散: 在每个表下面创建各自的 controller、service、dao、entity 目录
- 对于简单的项目,深度或广度都无所谓,都不要紧。
对于大型、复杂项目,尽量还是按照模块来。应该在每个模块下面创建各自的 controller、service、dao、entity 目录
不要出现奇怪的模块目录结构
每个模块目录结构如下:
controller、service、dao、entity、config、constant、util, 除此之外,尽量不应该出现其他目录。
注: 如果没有对应的类,可以不用创建那个目录。
需要Dto/Vo/Bo/Po/Param 吗
前端调用后端方法的时候,后端方法的接收参数需要封装吗? controller调用service、service调用dao 需要封装参数吗?需要封装返回值吗?
尽量还是不用Dto/Vo/Bo, 直接实体类即可。
当然如果,如果实体类满足不了业务需要,应当进行封装,统一使用 xxxDto
提炼公共组件
公共组件,能够提炼到公告地方的, 一定要提炼!! 可以减少臃肿,尽量实现通用
比如,很多地方都会使用到bool常量,如果我们每个模块都定义一遍,会显得非常的重复,这样的非常常见的、通用的工具、静态类、枚举,应当放到公共组件
RESTful 风格
- 完全的 RESTful 还是部分的? 尽量使用完全的RESTful!
- 但如果http方法冲突,那么不得已,url中也可以使用动词
- controller 方法参数是否需要封装? 不需要json封装,直接传递所需要的数据即可
- controller 方法返回什么? 返回json,完全的 json格式。 统一的字段: code、 msg、 data。 统一使用工具类:R
- 是否需要返回值状态码还是通过返回值的code 来表示?code需要尽量模拟 http协议对状态码的规定,如下:
操作成功:200
系统异常:500
网关异常:503
参数/客户端错误: 400
找不到资源: 404
Swagger风格
Swagger还是其他? 暂定
保留swagger 基本注解: @Api,但是不需要很详细
否则swagger 会导致代码臃肿,侵入太大
注释风格
简单的方法,不需要写,或者少写。 复杂方法,必须要写
写在 service 接口上还是 接口的实现类impl上?写在接口上即可,其他地方可以不用写.
通用字段处理
create_time create_by update_time update_by 应该自动处理。
如果没有业务属性, 可以不需要这些字段; 但如果有,那么就需要维护好
可以通过拦截器或框架来做比较好,不要手动维护,造成代码啰嗦臃肿。
对于create_time、update_time 时间字段,可以由数据库来维护
参数校验
普通的操作,参数校验可选,前端校验一下即可
重要的操作,前后端都需要做参数校验,
后端如何校验? 使用统一的注解,通过框架完成,而尽量不要手动进行校验
项目依赖管理
pom.xml 依赖应该统一由一个人管理,其他人只读不能修改; 统一一个地方维护
如果确实需要修改,应该由负责人确定,然后负责人来实施
pom.xml 的依赖应当尽量的简洁,不应该过多的重复
如何认证、鉴权?
注释风格, 统一处理. jwt token + redis
异常处理
不要到处 try catch,代码中尽量不出现异常处理!
统一到 ExceptionHandler 进行处理
如何分页
手动? pagehelper, 还是mybatis plus提供的?
必须使用mybatis框架自带的!
编码格式
数据库字符集 utf8mb4
数据库排序规则 utf8mb4_general_ci
我们仅仅数据库的字符集、排序规则 即可, 不需要给表、字段单独设置字符集、排序规则, 以免引起不一致。 尽量保持统一
项目的代码源文件,应该全部 utf8
maven依赖如何管理版本号,何时进行升级?
尽量不升级,如果有必要,则:
第三方的依赖: 统一升级;
自己的项目的升级: 按照项目、业务发展需要
如何记录日志?
Controller层的方法不用写任何日志,通过拦截器实现
serviceimpl层的方法, 按照业务需要写日志
dao/mapper/util层,及其他层的方法不用写任何日志
分支管理
开发: develop
测试: release
发布: main
大小写
尽量全部使用小写,方便阅读!
不管是表名、字段名、字段值、
包名、 变量名、 常量值 等等
其他
Mybatis plus 还是Mybatis?统一使用 Mybatis plus,可以减少sql编写。dao层尽量不写sql,因为难以维护, 尽量使用mybatis-plus提供的方法
mybatis plus2 还是3?3 !
所以实体对象使用lombok
fastjson 还是 jackson? 统一 fastjson
java.util.Date 还是 java.time.LocalDate ? 对于数据库字段,还是统一 java.util.Date , 因为这个兼容性好,工具生成的代码都是这个格式。
所有实体类统一继承基础实体类(跟随框架)
避免空值: controller、service、dao 的方法一律不能返回空值
使用静态常量还是枚举? 尽量减少枚举,因为可读性比较差
尽量使用标准组件、统一化, 如果有bug,那么也只是修改一个地方即可
尽量少写代码,没有代码自然不会有bug!
四、关于测试
复杂模块,尽量编写单元测试