注: 基于《JAVA开发手册》1.5.0

编程规约

  • url表示资源路径, 不能包含动词, 参数可以携带动词, 统一全局使用单数形式

说明: 比如 /user/enable表示”查询启用的用户”, /user?enable表示”启用用户”
常用增删改查标准示例如下:

  1. /**
  2. * @author xinzhang
  3. * @date 2021/04/10 15:07
  4. */
  5. public abstract class AbstractController<T extends BaseDO> {
  6. abstract BizService<T, LambdaQueryWrapper<T>> bizService();
  7. @PostMapping
  8. public void create(@RequestBody T entity) {
  9. bizService().create(entity);
  10. }
  11. @PutMapping("/{id}")
  12. public void modify(@PathVariable("id") Long id, @RequestBody T entity) {
  13. bizService().modify(entity);
  14. }
  15. @DeleteMapping("/{id}")
  16. public void remove(@PathVariable("id") Long id) {
  17. bizService().remove(id);
  18. }
  19. @GetMapping("/{id}")
  20. public T get(@PathVariable("id") Long id) {
  21. return bizService().get(id);
  22. }
  23. @GetMapping("/list")
  24. public List<T> list(T t) {
  25. return bizService().list(new LambdaQueryWrapper<>(t));
  26. }
  27. @GetMapping
  28. public IPage<T> page(T t, @RequestParam("page") int page, @RequestParam("size") int size) {
  29. return bizService().listPage(new LambdaQueryWrapper<>(t), page, size);
  30. }
  31. }
  • 全局使用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层为画蛇添足, 导致层次模糊

  • 一个”业务模块”可以跨级调用, 多个”业务模块”之间只能同级调用

说明: 比如存在费用申请模块与费用报销模块

  1. CostApplyService{ // 正确
  2. @Autowired
  3. CostApplyDao costApplyDao;
  4. @Autowired
  5. CostApplyDetailDao costApplyDetailDao;
  6. ...
  7. }
  8. CostReimburseService{
  9. @Autowired
  10. CostApplyService costApplyService;
  11. @Autowired
  12. CostApplyDao costApplyDao; // 错误
  13. ...
  14. }
  15. 补充:
  16. 通常情况下明细无需Service定义, 当明细的逻辑非常复杂时, 可以独立出接口, 比如CostApplyDetailService
  17. 此时CostReimburseService可以调用CostApplyDetailService
  • 全局需统一记录日志形式, 并下落日志文件