Skip to content

【案例】编码规范

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

编程规约

  • url****表示资源路径, 不能包含动词, 参数可以携带动词, 统一全局使用单数形式 说明: 比如 /user/enable表示"查询启用的用户", /user?enable表示"启用用户" 常用增删改查标准示例如下:
Java
/**
 * @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层为画蛇添足, 导致层次模糊

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

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

Java
CostApplyService{ // 正确
    @Autowired
    CostApplyDao costApplyDao;
    @Autowired
    CostApplyDetailDao costApplyDetailDao;
    ...
}

CostReimburseService{
    @Autowired 
    CostApplyService costApplyService;
    @Autowired
    CostApplyDao costApplyDao; // 错误
    ...
}

补充: 
通常情况下明细无需Service定义, 当明细的逻辑非常复杂时, 可以独立出接口, 比如CostApplyDetailService
此时CostReimburseService可以调用CostApplyDetailService
  • 全局需统一记录日志形式, 并下落日志文件