编程规约
- url表示资源路径, 不能包含动词, 参数可以携带动词, 统一全局使用单数形式
说明: 比如 /user/enable表示”查询启用的用户”, /user?enable表示”启用用户”
常用增删改查标准示例如下:
/**
* @author xinzhang
* @date 2021/04/10 15:07
*/
public abstract class AbstractController<T extends BaseDO> {
abstract BizService<T, LambdaQueryWrapper<T>> bizService();
@PostMapping
public void create(@RequestBody T entity) {
bizService().create(entity);
}
@PutMapping("/{id}")
public void modify(@PathVariable("id") Long id, @RequestBody T entity) {
bizService().modify(entity);
}
@DeleteMapping("/{id}")
public void remove(@PathVariable("id") Long id) {
bizService().remove(id);
}
@GetMapping("/{id}")
public T get(@PathVariable("id") Long id) {
return bizService().get(id);
}
@GetMapping("/list")
public List<T> list(T t) {
return bizService().list(new LambdaQueryWrapper<>(t));
}
@GetMapping
public IPage<T> page(T t, @RequestParam("page") int page, @RequestParam("size") int size) {
return bizService().listPage(new LambdaQueryWrapper<>(t), page, size);
}
}
- 全局使用BO对象, 禁用DO, VO, DTO等.
说明: BO~Business Object通用的业务对象; 建立VO等对象会降低接口通用性.
POJO类中布尔类型变量一律不加is前缀, 数据库表布尔类型必须加is前缀, 在resultMap中设置从is_xxx到xxx的映射关系.
包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用单数形式. 类名也统一使用单数形式.
命名力图”见名知意”, 杜绝不规范的缩写. 特别常量力图语义表达清晰, 不要嫌名字长. 以及注意自定义编程元素, 不能使用毫无意义的简称.
反例: int a
枚举以及数据字典统一形式, 由统一接口交互.
方法命名前缀
- 获取单个对象: get
- 获取多个对象: list, 多个依旧以单数形式命名, 如listUser
- 获取分页多个对象: listPage
- 获取统计值: count
- 新增: create
- 修改: modify
- 删除: remove
不允许任何魔法值( 即未经预先定义的常量) 直接出现在代码中
统一全局使用的工具类, 如StringUtil, CollectionUtil, BooleanUtil等
不能存在任何编译警告, 如果有, 用注解@SuppressWarnings压制具体片段, 并给出明确注释
集合初始化时, 需要指定初始化大小
说明: HashMap 使用 HashMap(int initialCapacity) 初始化 , initialCapacity = (需要存储的元素个数 / 负载因子) + 1。 注意负载因子(即 loader factor) 默认为 0.75,如果暂时无法确定初始值大小,请设置为 16(即默认值) .
垃圾或过时代码及时清理
DRY ( Don’t Repeat Yourself) 原则 , 避免出现重复的代码, 必要时抽取共性方法,或者抽象公共类,甚至是组件化
禁用BeanUtil.copyProperties()
数据库
设计cdm再转为pdm, 代码生成器拉分支, cdm文件与该分支一同进行版本管理
每张表必须指定主键索引, 编码字段必须指定唯一索引, 业务非空字段必须指定非空约束, 建表时就应考虑建立普通索引
库名与应用名称尽量一致, 表名遵循”业务名称_表名”, 表必备字段”create_time”, “update_time”.
不要”反常识”设计, 不要”超前设计”, 架构设计三原则, “简单”, “合适”, “演进”.
反例:
- 日期用数字或字符串存储, 导致后续进行日期新增, 比较都极为不便, 且不走索引
- 为了前端显示, 单独加个字段转成显示效果
- 超前考虑产品的拓展, 将一对一设计成多对多, 极大增加了编程复杂度
- 含义相同的字段名应全局一致, 同理, 精确含义不同应区别命名
说明: 比如cost_apply_code与cost_reimburse_code同为编码, 但是不同单据, 应该区别命名
工程结构
- 工程搭建应使用模块化与分层理念
说明: 示例工程结构如下
ei-project
- ei-project-biz 业务接口, 包括service, dao层
- ei-project-schema 实体结构, 放置DO, BO, ENUM等全局通用对象
- ei-project-web web接口, 包括controller
- ei-project-util 工具类
- ei-project-bridge 第三方交互, 比如与金蝶, 与HR系统交互
…
反例: 深高顾的biz和service定义冲突, biz层为画蛇添足, 导致层次模糊
- 一个”业务模块”可以跨级调用, 多个”业务模块”之间只能同级调用
说明: 比如存在费用申请模块与费用报销模块
CostApplyService{ // 正确
@Autowired
CostApplyDao costApplyDao;
@Autowired
CostApplyDetailDao costApplyDetailDao;
...
}
CostReimburseService{
@Autowired
CostApplyService costApplyService;
@Autowired
CostApplyDao costApplyDao; // 错误
...
}
补充:
通常情况下明细无需Service定义, 当明细的逻辑非常复杂时, 可以独立出接口, 比如CostApplyDetailService
此时CostReimburseService可以调用CostApplyDetailService
- 全局需统一记录日志形式, 并下落日志文件