振瀚项目开发规范(后端)


概述

我们以 阿里巴巴开发手册 为基础, 结合自己工作经验, 作为所有项目的开发规范, 以此为约束, 希望构建一个个 稳定, 易于维护, 可扩展 的系统.

一个项目最怕多种编码风格, 实体名一会 entity, 一会 model, 让维护的人身心疲惫, 因此在一个项目中保持唯一一种编码习惯, 有利于代码维护与快速理解, 比如通过命名, 就知道其大概的作用以及所在的包名.

见名知意, 此乃命名的最高境界(体会一下 取名一小时, 编码一分钟 的境界 😂).

代码规范看起来比较枯燥, 看完一遍可能只有一点点印象, 因此希望大家多看几遍. 代码规范比较偏向个人主义, 每个人的编码习惯都不一样, 所以希望多提出自己的建议, 一起改进(没有最好的规范, 只有最合适的. 🙃)

Let’s go开篇

江湖四分五裂, 一人一江湖…

但我们是一个团队,为了便于管理和维护,急需一份代码规范, 来约束我们的编码规则和习惯, 就像修炼一门武林绝学, 需要秘籍的指引(葵花宝典?)。

请各位英雄好汉仔细阅读并严格遵守. 如有不足之处 希望提出意见, 共商武林统一霸业.

从 1000 个哈姆雷特转变为同一个 林志玲, 代码风格保持统一有利于提高工作效率, 便于管理.

比如:

  1. 一看到以 Rest结尾的类, 就应该知道这个是接口, 用于参数验证, 业务逻辑转发, 组装结果, 返回规范的数据结构或跳转页面;

  2. 一看到以 Controller 结尾的类, 就应该知道这个是接口, 用于参数验证, 业务逻辑转发, 组装结果, 返回规范的数据结构或跳转页面;

  3. 一看到以 Service 结尾的类, 就知道这个是业务接口类, 用于定义业务接口;

  4. 一看到以 Impl 结尾的类, 就应该知道这个是业务实现类, 组合不同的 Dao, 实现业务逻辑;

  5. 一看到以 mapper 结尾的类, 就应该知道这个是 DB 操作类, 对数据进行 CRUD 操作;

  6. 一看到以 DTO 结尾的类, 就应该知道这个是数据传输对象, 用于展示层和服务层之间的数据传输;

  7. 一看到以 Entity 结尾的类, 就应该知道这个是数据库的映射对象, 用于系统和数据库之间的数据传输;

  8. ….

约定

为了避免歧义, 文档大量使用以下词汇, 解释如下:

  1. 必须 (must): 绝对,严格遵循,请照做,无条件遵守;

  2. 一定不可 (must not): 禁令,严令禁止;

  3. 应该 (should): 强烈建议这样做,但是不强求;

  4. 不该 (should not): 强烈不建议这样做,但是不强求;

  5. 可以 (may) 和 可选 (optional): 选择性高一点,在这个文档内,此词语使用较少;

  6. 推荐 (recommend): 个人推荐的做法, 不强求;

准备工作

行走江湖, 没有一件趁手的兵器怎么能在江湖中立足, 还在用 eclipse 的少侠们, 希望弃暗投明, 拥抱 Intellij IDEA, 你会发现编码效率提升不是点巴点儿, 而是蹭蹭蹭的往上涨 😁.

我不是富二代, 我没有赢在人生的起跑线上, 但是我用 Intellij IDEA, 我赢在了工作的起跑线上!

推荐一个比较全面的 Intellij IDEA 教程, 请大家一定要花点时间熟悉或配置一下自己的 IDEA.

目前 JetBrains 家的所有产品全线支持中文, 只需要下载官方中文语言包即可, 个人推荐使用中文包 (会有种发现新大陆的感觉).

这里值得吐槽一下, 官方没出中文汉化包之前到处找第三方汉化包, 出了官方汉化包后又觉得用汉化版 low, IDE 用英文版才显得高大上 😢.

我们是工作, 应该使用各种工具提高自己的开发效率, 官方都贴心的为我们提供了母语支持, 我们反而不用了, 有点对不起使用这么多年 盗版的 IDEA 呀.

以上是个人意见, 大家随意选择, 如果以后需要我帮你在本地处理 IDEA 的问题, 请先安装汉化包.

工欲善其事, 必先利其器. 一件趁手的兵器带你迎娶白富美, 走上人生巅峰, 统一江湖, 指日可待

为了简化手动操作和提高编码效率, 我们要求 必须 安装几个必要的插件, 以及对 IDEA 进行必要的优化配置.

Intellij IDEA 插件

Alibaba Java Coding Guidelines

可以 安装

作用: 代码规则检查

此插件是 阿里巴巴根据 阿里巴巴开发手册 开发的一个静态代码规范检查插件, 每个警告都提供了一个 demo,

此篇以 阿里巴巴开发手册 为基础, 但是并不会一一罗列每条规范, 因为此插件已经能很好的检查了.

Lombok

必须 安装, 不然代码跑不起来就尴尬了

作用: 化繁为简. 官网

使用 @Data 代替烦人的 get/set 方法

使用 @Slf4j 代替获取 log 实例的代码

private static final Logger log = LoggerFactory.getLogger(ApplicationTest.class);

从 IDEA 2020.3 开始 lombok 作为 IDEA 内置插件, 因为 lombok 跟 IDEA 版本存在兼容性问题, 请一定要使用内置版本, 如果 IDEA 在 2020.3 以下, 请尽快升级到 2022以上版本, 注册码问题请自行解决,感觉麻烦的同学自行淘宝。

如果因为 lombok 导致编译失败, 请开启 注解处理器 配置, 如果还是不行, 请删除 .idea 和 .iml 并重新导入, 这样基本上能解决 IDEA 大多数编译问题.

Maven Helper

必须的必须 安装, 如果发现没有安装的, 罚写 1000 遍 Maven Helper (不准用 for 和 while)

作用: 检查依赖冲突, 项目依赖分析 , 简化 Maven 命令

新加入一个 jar 包, 谁添加谁负责, 使用此插件检查是否有依赖冲突.

依赖冲突可能会导致:

  1. java.lang.ClassNotFoundException

  2. java.lang.NoSuchMethodError

  3. java.lang.NoClassDefFoundError

  4. 开发环境正常, 线上环境不正常….

固化 Maven 命令

这里面的 -Dcheckstyle.skip 和 -Dpmd.skip 请大家不要随意使用, 要是发现提交的代码编译不通过请大家喝奶茶就行.

JRebel

推荐 安装, 提高工作效率的插件.

作用: 代码热部署插件, 改了代码后, 重新编译, 不用重启应用就可查看效果.

热部署插件, 谁用谁知道;

GenerateSerialVersionUID

推荐 安装

作用: 为实现了 Serializable 接口的实体快速添加 serialVersionUID, 提高效率

实体了 Serializable 接口的实体, 必须 添加 serialVersionUID 字段.

GenerateAllSetter

推荐 安装

作用: 快速生成 set 方法

RestfulToolkit

推荐 安装

作用: 快速定位接口, Rest 请求模拟

Restful Fast Request - API Buddy

推荐 安装

作用: 快速请求生成文档等

Archive Browser

推荐 安装

作用: 在 IDEA 中直接查看压缩包类的文件, 不需要解压

arthas idea

推荐 安装

作用: 如果你玩儿 arthas, 推荐安装此插件

CodeGlance2

推荐 安装

作用: 在 IDEA 编辑框右边生成一个 mini map, 用于快速导航.

aiXcoder

推荐 安装

作用: 基于 AI 的代码自动补全与搜索代码示例插件,有钱或者爱折腾的朋友推荐你玩儿GitHub copilot

Conventional Commit

推荐 安装

作用: 自动补全 git commit 前缀, 配合 FKH.Kit.Commit 使用提升体验

CSDN tools

推荐 安装

作用: 免费的开发者工具, Json 格式化, 时间转换

Diagrams.net Integration

推荐 安装

作用: IDEA 插件版的 draw.io, 可直接编辑 svg 文件

推荐使用此插件代替桌面版的 draw, 不要再发截图了, 以后可直接编辑原文件

GitToolBox

必须 安装

作用: 直观的看到每一行的提交记录, 自动提示有远端代码提交, 它不香吗?

JProfiler/VisualVM Launcher/VisualGC/YourKit

推荐 安装 JProfiler , YourKit 不好弄, 还没找到共享版.

作用: 启动为什么慢如蜗牛? deadlock 发生在哪里? JVM 为何频频 OOM? 是道德的沦丧还是人性的扭曲? 用用 JProfiler 就知道了.

JProfiler

VisualGC

JWT

必须 安装

作用: 直接解析 token 内的数据

MybatisCodeHelperPro

推荐的推荐 安装

作用: 自己去看看 提供多少功能, 能给我们提高多少开发效率, 一年 60 块 2 个激活码, 反正我是买了, 支持一下国内开发者吧, 哪天你开发了一个我也买.

Save Actions

推荐的推荐 安装

作用: 手动保存文件之前执行一些自定义操作, 比如添加 this, 格式化代码, 删除无用 import 等.

Spot Profiler for Java and Kotlin

推荐 安装

作用: 想知道某段代码执行的时间? 使用 Stopwatch 输出后上线时搞忘了删除? 用这个吧.

SequenceDiagram

推荐 安装

作用: 根据代码调用逻辑自动生成时序图, 快速梳理代码逻辑的利器

Intellij IDEA 设置

还是推荐大家先看看 Intellij IDEA 教程, 对 IDEA 的配置有一个整体的了解, 接下来将介绍一下个人觉得有用但是大家一直没有去很好的设置的地方.

启动时重新打开项目

经常看到启动 IDEA 时自动打开了最后关闭的项目, 为什么不在启动的时候自己选择呢? 难道最后一个关闭的项目就一定是我们想打开的嘛?

取消 启动时重新打开项目 选项

启动时你就能看到这个页面, 这里再选择它不香吗?

Maven 环境配置

经常看到第一次打开新项目的时候还要手动去修改 Maven 的环境配置, 了解一下 项目级配置:

这里面的配置将会作为所有 新项目 的默认配置, 不用每次都去修改了, 多节约点时间回家撸猫不好吗?

记得再看看 为新项目运行配置模板 和 新项目的结构 这些配置, 多看看总是有好处的.

Git 操作

请注意, 在不是非常熟悉 git 命令的情况下, 不要在公司使用 git 命令行操作代码, 可以回家自己玩儿, 辛苦一天写的代码丢了就不好玩儿了 (如果无所谓我怀疑你在摸鱼).

我推荐大家使用图形化界面的方式去操作 Git, 我们不会觉得这样不高级, 面试的时候也没人会问你 Git 拉取分支的命令是什么 (要是真有人问, 你就反问 Git 的实现原理是什么? 指针与引用的区别又是什么? 然后带上微笑默默地走出办公室, 深藏功与名 😎).

Git Patch/Cherry-Pick

想从某个分支合并某一条或几条 commit? 用用 Cherry-Pick 吧. 在家修改了代码不能提交到公司仓库? 用用 Patch 吧.

Cherry-Pick

Patch

配置备份

如果不想重复配置, 如果想让公司的配置和家里的配置保持同步, 试试这个吧, 推荐使用 Gitee 同步配置, 不过一定要记得 设置为私有项目.

代码快速执行

如果想临时快速的验证某一段代码, 直接用 JShell(JDK11+) 或 Groovy 吧, 不用再写单元测试了.

其他的快捷键根据习惯自己设置吧.

多用快捷键

多用快捷键

多用快捷键

并且必须在提交代码前保证能通过编译(能运行不代表代码检查通过), 可以手动执行 mvn clean validate.

个人认为代码规范是在 编码过程中去下意识遵守的 , 而不是因为项目工期紧就去忽略这一项工作, 后期再花几天时间去改代码格式, 请一定要记住这个逻辑.其实这就是一个编码习惯的问题, 前期可能不习惯经常忘记, 后面就好了, 不过一定要下意识的按照代码规范写代码, 只有这样才能养成习惯.

开发规范

后端开发规范

整体规范:

所有的项目名称、模块名称、包名等均使用英文小写。项目名称、模块名称单词之间采用 - 分隔,尽量见名知意,禁止使用拼音,同时也不要随意进行不常规的简写。不要随心所欲的命名, 要讲究的规则, 不然会走火入魔的.

项目名:

  • 所有的振瀚信息项目必须以此开头: zh-(例:zh-)

  • 在后面跟上项目的性质:

    • 外部单体项目:zh-single

    • 前台普通业务:zh-biz

    • 中台项目:zh-center

  • 最后跟上自己实际的项目名(例:zh-biz-budget)

模块名:

  • 所有的振瀚信息项目模块必须以此开头:实际的项目名-(例:budget-)

  • 在实际的项目名后面跟上模块性质

    • 核心模块:budget-cservice(core-service的简称)

    • 公共模块:budget-common

    • sdk模块:budget-sdk

    • 后台管理模块:budget-manage-mservice(more-service的简称)

    • 服务暴露模块:budget-rest-mservice(more-service的简称)

    • 扩展模块:在上述第二项后面跟上具体的扩展模块名再跟上扩展服务标识:budget-statistics-mservice(more-service的简称)

从上述分包中可以看出,我们所有可以运行的包均是以service作为结尾的,所以在创建模块的时候一定要注意进行区分。虽然我们提倡微服务,解耦合,功能聚焦。但是我们反对毫无设计,不分场景的分包分模块。模块的划分是一把双刃剑,每一位项目管理人员都应该对自己的项目结构和代码质量负责。

包名:

所有的包名必须以com.zhxx开头,不能以其他开头

其他规则:

  • 核心模块: com.zhxx.实际项目名.服务名(例:com.zhxx.payment.cservice)

  • 公共模块: com.zhxx.实际项目名.服务名(例:com.zhxx.payment.common)

  • 扩展模块: com.zhxx.实际项目名.服务名(例:com..zhxx.payment.statistics.mservice)

  • sdk模块:com.zhxx.实际项目名.服务名(例:com..zhxx.payment.sdk)

推荐几个常用的包名:

  • config 用来放配置类

  • util 工具类包

  • enums 枚举类包

  • constant 常量类包 (推荐 将常量按类别定义在不同的常量类中)

  • service service 接口包

  • service.impl service 接口实现类包

  • dao dao 接口包

  • feign 特指单独 feign 提供的接口类

  • rest 特指 rest api

  • moudel 可以在上述模块下区分不同的业务线条使用的包名

类名:

类名 必须 使用 UpperCamelCase 风格(首字母都大写),必须遵从驼峰形式. 例如: StringUtils

抽象类命名 必须 使用 Abstract 或 Base 开头; 异常类命名 必须 使用 Exception 结尾; 测试类命名 必须 以它要测试的类的名称开始,以 Test 结尾; 接口实现类 必须 以 Impl 结尾; API 接口类必须以 Controller 结尾; ORM接口必须以 Dao 结尾;

方法名:

接口名 推荐 使用以下命名方式

新增:

  • add(Entity entity)

  • insert(Entity entity)

  • save(Entity entity)

查询:

  • get(Long id)

  • getByXxx

  • findByXxx

  • selectByXxx

更新:

  • update(Entity entity)

  • updateByXxx

删除:

  • delete(Long id)

  • deleteByXxx

属性名:

这个没什么好说的, 按照 Java 推荐命名方式即可.常量命名 必须 全部大写, 单词间用下划线分隔;

注入规范:

在项目开发的过程中,不可避免的需要使用到大量的注入,我们在此进行约定,业务项目中 建议使用构造注入的方式,架构(组件)项目中 必须使用构造注入的方式;

微服务(包)的划分:

所有微服务的划分必须 经过项目经理的同意,禁止自己擅自新建微服务,微服务建设应该遵循以下原则:

  • 复用性:即该微服务的划分,是确实存在两个或者以上的服务需要本服务以独立服务的方式提供能力支持。

  • 可用性:当前整体架构服务存在高可用,多点多活的特性化需求。

  • 可插拔:满足单一职责或者领域模型,同时项目真实存在有热插拔的需求。

数据库规范:

推荐 3 篇文章, 虽然是 mysql 的, 但是都是数据库啊

赶集 mysql 军规 58到家数据库30条军规解读 再议数据库军规

代码生成器:

必须 使用easyCode代码生成器,且必须使用公司已经设计好的模板禁止自己随意扩展。

文档对接工具:

项目框架中已经完成了swagger的继承,只需要在项目地址:端口/doc.html,即可访问

pom 规范:

groupId 必须 为 com.zhxx artifactId 必须 与 模块名相同 version 必须 与 父 pom version 相同 必须 显式指定 packaging

如果没有设置 packaging 标签, 默认打包为 jar 格式, 这里 必须 设置此标签, 明确指定打包格式.

建议 写 description 标签

为此 pom 添加必要的描述信息

第三方依赖 必须 添加到 父级项目的 pom 中; 如果 Maven 中央仓库没有的 jar 包, 从网上下载后, 必须 上传到公司的 Maven, 不能直接使用 jar 包

  1. 搜索 Maven 中央仓库, 关键字 + maven;

  2. 搜索不到则找到 jar 上传到公司 Maven 仓库(联系运维或者架构组同学)

日志规范:

推荐 使用 @Slf4j 获取 log 实例

使用 lombok 插件, 直接使用 @Slf4j 代替获取 log 实例的冗余代码.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
​
...
private static final Logger log = LoggerFactory.getLogger(Xxx.class);

必须 使用 log4j2 日志框架

统一使用效率更高的 log4j2 日志框架

日志输出到文件的编码 必须 为 UTF-8

日志配置名:

Web 应用或者通过 JVM 进程提供服务的应用, 必须 使用 log4j2-spring.xml 命名

Spring Boot 官方推荐优先使用带有 -spring 的文件名作为日志配置(如使用 log4j2-spring.xml,而不是 log4j2.xml)

原理可以查看 Log4J2LoggingSystem.getCurrentlySupportedConfigLocations() AbstractLoggingSystem.getSpringConfigLocations()

输出样式:

env: %d{yyyy.MM.dd HH:mm:ss.SSS} [%5p] ${sys:PID} -- [%15.15t] %-40.40c{1.} : %m%n%xwEx

输出内容元素具体如下:

  • 环境名

  • 时间日期 — 精确到毫秒

  • 日志级别 — ERROR, WARN, INFO, DEBUG or TRACE

  • 进程ID

  • 分隔符 — -- 标识实际日志的开始

  • 线程名 — 方括号括起来(可能会截断控制台输出)

  • Logger名 — 通常使用源代码的类名

  • 日志内容

效果 :

dev: 2018.08.01 15:02:25.153  INFO 75012 -- [  restartedMain] c.i.m.m.MeetingApplication : Starting MeetingApplication on dong4j with PID 75012 (/Users/codeai/Develop/work/ifly/musicsearch-project/musicsearch-business/service-meeting/target/classes started by codeai in /Users/codeai/Develop/work/ifly/musicsearch-project)
dev: 2018.08.01 15:02:25.154 DEBUG 75012 -- [ restartedMain] c.i.m.m.MeetingApplication : Running with Spring Boot v1.5.8.RELEASE, Spring v4.3.12.RELEASE
dev: 2018.08.01 15:02:25.155 INFO 75012 -- [ restartedMain] c.i.m.m.MeetingApplication : The following profiles are active: oracle

前端开发规范:

测试规范: