Files
smart-admin/代码规范/java-standard-guide.md
“zhuoda 51120222a7 v1.0.0
2019-11-17 22:04:11 +08:00

698 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# JAVA 开发规范
> _v1.0.0 2019/09/06_
本篇规范基于阿里巴巴、华为的开发手册,添加了我们团队的开发风格规范,补充了一些细节。感谢前人的经验和付出,让我们可以有机会站在巨人的肩膀上眺望星辰大海。
规范不是为了约束和禁锢大家的创造力,而是为了帮助大家能够在正确的道路上,尽可能的避免踩坑和跑偏。
规范可以让我们无论单枪匹马还是与众人同行的时候都能得心应手。
规范可以让我们在面对日益变态的需求和做代码接盘侠的时候,更优雅从容。
规则并不是完美的,通过约束和禁止在特定情况下的特性,可能会对代码实现造成影响。
但是我们制定规则的目的:**为了大多数程序员小伙伴可以得到更多的好处**,如果在团队实际运作中认为某个规则无法遵循或有更好的做法,希望大家可以共同改进该规范。
## 一、编程规范
### 1、好代码的原则
我们参考 Kent Beck 的简单设计四原则来指导我们的如何写出优秀的代码,如何有效地判断我们的代码是优秀的。
- 通过所有测试Passes its tests强调的是外部需求这是代码实现最重要的
- 尽可能消除重复 (Minimizes duplication):代码的模块架构设计,保证代码的正交性,保证代码更容易修改
- 尽可能清晰表达 (Maximizes clarity):代码的可阅读性,保证代码是容易阅读的
- 更少代码元素 (Has fewer elements):保证代码是简洁的,在简洁和表达力之间,我们更看重表达力
以上四个原则的重要程度依次降低, 这组定义被称做简单设计原则。
### 2、项目命名规范
全部采用小写方式, 以中划线分隔。
正例:`mall-management-system / order-service-client / user-api`
反例:`mall_management-system / mallManagementSystem / orderServiceClient`
### 3、TODO/FIXME 规范
`TODO/TBD(to be determined)` 注释一般用来描述已知待改进、待补充的修改点,并且加上作者名称。
`FIXME` 注释一般用来描述已知缺陷,它们都应该有统一风格,方便文本搜索统一处理。如:
```java
// TODO <author-name>: 补充XX处理
// FIXME <author-name>: XX缺陷
```
### 4、方法参数规范
无论是 `controllerservicemanagerdao` 亦或是其他的代码,每个方法最多 `3` 个参数,如果超出 `3` 个参数的话,要封装成 `javabean` 对象。
1. 方便他人调用,降低出错几率。尤其是当参数是同一种类型,仅仅依靠顺序区分,稍有不慎便是灾难性后果,而且排查起来也极其恶心。
2. 保持代码整洁、清晰度。当一个个方法里充斥着一堆堆参数的时候,再坚强的人,也会身心疲惫。
反例:
```java
/**
* 使用证书加密数据工具方法
*
* @param param
* @param password 加密密码
* @param priCert 私钥
* @param pubCert 公钥
* @return 返回加密后的字符串
*/
public String signEnvelop(JdRequestParam param, String password, String priCert, String pubCert){}
```
### 5、注释规范
#### 5-1、注释和代码一样重要
注释是我们披荆斩棘历经磨难翻越需求这座大山时,留下的踪迹和收获的经验教训,这些宝贵的知识除了证明我们曾经存在过,也提醒着后来的人们殷鉴不远、继往开来。
注释除了说明作用、逻辑之外。还有一个很重要的原因:当业务逻辑过于复杂,代码过于庞大的时候,注释就变成了一道道美化环境、分离与整理逻辑思路的路标。这是很重要的一点,它能有效得帮助我们免于陷入代码与业务逻辑的泥沼之中。
正例:
```java
/**
* 开始抽奖方法
* 保存中奖信息、奖励用户积分等
* @param luckDrawDTO
* @return ResponseDTO 返回中奖信息
*/
public ResponseDTO<String> startLuckDraw(LuckDrawDTO luckDrawDTO) {
// -------------- 1、校验抽奖活动基本信息 ------------------------
xxx伪代码一顿操作
// -------------- 2、新增抽奖记录 -------------------------------
xxx伪代码一顿操作
// -------------- 3、如果需要消耗积分则扣除钢镚积分 -------------
xxx伪代码一顿操作
// -------------- 4、获取奖品信息开始翻滚吧 --------------------
xxx伪代码一顿操作
return ResponseDTO.succ(luckDrawPrizeVO);
}
```
#### 5-2、注释和代码的一致性
注释并不是越多越好,当注释过多,维护代码的同时,还需要维护注释,不仅变成了一种负担,也与我们当初添加注释的初衷背道而驰。
首先:大家应该通过清晰的逻辑架构,好的变量命名来提高代码可读性;需要的时候,才辅以注释说明。注释是为了帮助阅读者快速读懂代码,所以要从读者的角度出发,按需注释。注释内容要简洁、明了、无二义性,信息全面且不冗余。
其次:无论是修改、复制代码时,都要仔细核对注释内容是否正确。只改代码,不改注释是一种不文明行为,破坏了代码与注释的一致性,会让阅读者迷惑、费解,甚至误解。
反例:
```java
// 查询部门
EmployeeDTO employee = employeeDao.listByDeptId(deptId);
```
#### 5-3、方法注释
方法要尽量通过方法名自解释,不要写无用、信息冗余的方法头,不要写空有格式的方法头注释。
方法头注释内容可选,但不限于:功能说明、返回值,用法、算法实现等等。尤其是对外的方法接口声明,其注释,应当将重要、有用的信息表达清楚。
正例:
```java
/**
* 解析转换时间字符串为 LocalDate 时间类
* 调用前必须校验字符串格式 否则可能造成解析失败的错误异常
*
* @param dateStr 必须是 yyyy-MM-dd 格式的字符串
* @return LocalDate
*/
public static LocalDate parseYMD(String dateStr){}
```
反例:
```java
/**
* 校验对象
*
* @param t
* @return String
*/
public static <T> String checkObj(T t);
```
反例中出现的问题:
- 方法注释没有说明具体的作用、使用事项。
- 参数、返回值,空有格式没内容。这是非常重要一点,任何人调用任何方法之前都需要知道方法对参数的要求,以及返回值是什么。
## 二、项目规范
### 1、代码目录结构
统一的目录结构是所有项目的基础。
```
src 源码目录
|-- common 各个项目的通用类库
|-- config 项目的配置信息
|-- constant 全局公共常量
|-- handler 全局处理器
|-- interceptor 全局连接器
|-- listener 全局监听器
|-- module 各个业务
|-- |--- employee 员工模块
|-- |--- role 角色模块
|-- |--- login 登录模块
|-- third 三方服务比如redis, oss微信sdk等等
|-- util 全局工具类
|-- Application.java 启动类
```
### 2、common 目录规范
common 目录用于存放各个项目通用的项目,但是又可以依照项目进行特定的修改。
```
src 源码目录
|-- common 各个项目的通用类库
|-- |--- anno 通用注解,比如权限,登录等等
|-- |--- constant 通用常量,比如 ResponseCodeConst
|-- |--- domain 全局的 javabean比如 BaseEntity,PageParamDTO 等
|-- |--- exception 全局异常,如 BusinessException
|-- |--- json json 类库,如 LongJsonDeserializerLongJsonSerializer
|-- |--- swagger swagger 文档
|-- |--- validator 适合各个项目的通用 validator如 CheckEnumCheckBigDecimal 等
```
### 3、config 目录规范
config 目录用于存放各个项目通用的项目,但是又可以依照项目进行特定的修改。
```
src 源码目录
|-- config 项目的所有配置信息
|-- |--- MvcConfig mvc的相关配置如interceptor,filter等
|-- |--- DataSourceConfig 数据库连接池的配置
|-- |--- MybatisConfig mybatis的配置
|-- |--- .... 其他
```
### 4、module 目录规范
module 目录里写项目的各个业务,每个业务一个独立的顶级文件夹,在文件里进行 mvc 的相关划分。
其中domain 包里存放 entity, dto, vobo 等 javabean 对象
```
src
|-- module 所有业务模块
|-- |-- role 角色模块
|-- |-- |--RoleController.java controller
|-- |-- |--RoleConst.java role相关的常量
|-- |-- |--RoleService.java service
|-- |-- |--RoleDao.java dao
|-- |-- |--domain domain
|-- |-- |-- |-- RoleEntity.java 表对应实体
|-- |-- |-- |-- RoleDTO.java dto对象
|-- |-- |-- |-- RoleVO.java 返回对象
|-- |-- employee 员工模块
|-- |-- login 登录模块
|-- |-- email 邮件模块
|-- |-- .... 其他
```
### 5、 domain 包中的 javabean 命名规范
1 `javabean` 的整体要求:
- 不得有任何的业务逻辑或者计算
- 基本数据类型必须使用包装类型`Integer, Double、Boolean 等)`
- 不允许有任何的默认值
- 每个属性必须添加注释,并且必须使用多行注释。
- 必须使用 `lombok` 简化 `getter/setter` 方法
- 建议对象使用 `lombok``@Builder @NoArgsConstructor`同时使用这两个注解简化对象构造方法以及set方法。
正例:
```java
@Builder
@NoArgsConstructor
@Data
public class DemoDTO {
private String name;
private Integer age;
}
// 使用示例:
DemoDTO demo = DemoDTO.builder()
.name("yeqiu")
.age(66)
.build();
```
2数据对象`XxxxEntity`,要求:
-`Entity` 为结尾(阿里是为 DO 为结尾)
- Xxxx 与数据库表名保持一致
- 类中字段要与数据库字段保持一致,不能缺失或者多余
- 类中的每个字段添加注释,并与数据库注释保持一致
- 不允许有组合
- 项目内的日期类型必须统一,建议使用 `java.util.Datejava.sql.Timestampjava.time.LocalDateTime` 其中只一。
3传输对象`XxxxDTO`,要求:
- 不可以继承自 `Entity`
- `DTO` 可以继承、组合其他 `DTOVOBO` 等对象
- `DTO` 只能用于前端、RPC 的请求参数
3视图对象`XxxxVO`,要求:
- 不可继承自 `Entity`
- `VO` 可以继承、组合其他 `DTOVOBO` 等对象
- `VO` 只能用于返回前端、rpc 的业务数据封装对象
4业务对象 `BO`,要求:
- 不可以继承自 `Entity`
- `BO` 对象只能用于 `servicemanagerdao` 层,不得用于 `controller`
## 三、MVC 规范
### 1、整体分层
- controller 层
- service 层
- manager 层
- dao 层
### 2、 `controller` 层规范
1 只允许在 method 上添加 `RequestMapping` 注解,不允许加在 class 上(为了方便的查找 url放到 url 不能一次性查找出来)
正例:
```java
@RestController
public class DepartmentController {
@GetMapping("/department/list")
public ResponseDTO<List<DepartmentVO>> listDepartment() {
return departmentService.listDepartment();
}
```
反例:
```java
@RequestMapping ("/department")
public class DepartmentController {
@GetMapping("/list")
public ResponseDTO<List<DepartmentVO>> listDepartment() {
return departmentService.listDepartment();
}
```
2不推荐使用 rest 命名 url 只能使用 `get/post` 方法。url 命名上规范如下:
> _虽然 Rest 大法好,但是有时并不能一眼根据 url 看出来是什么操作所以我们选择了后者这个没有对与错只有哪个更适合我们的团队。_
`/业务模块/子模块/动作`
正例:
```java
GET /department/get/{id} 查询某个部门详细信息
POST /department/query 复杂查询
POST /department/add 添加部门
POST /department/update 更新部门
GET /department/delete/{id} 删除部门
```
3每个方法必须添加 `swagger` 文档注解 `@ApiOperation` ,并填写接口描述信息,描述最后必须加上作者信息 `@author 哪吒`
正例:
```java
@ApiOperation("更新部门信息 @author 哪吒")
@PostMapping("/department/update")
public ResponseDTO<String> updateDepartment(@Valid @RequestBody DeptUpdateDTO deptUpdateDTO) {
return departmentService.updateDepartment(deptUpdateDTO);
}
```
4controller 负责协同和委派业务,充当路由的角色,每个方法要保持简洁:
- 不做任何的业务逻辑操作
- 不做任何的参数、业务校验,参数校验只允许使用@Valid 注解做简单的校验
- 不做任何的数据组合、拼装、赋值等操作
正例:
```java
@ApiOperation("添加部门 @author 哪吒")
@PostMapping("/department/add")
public ResponseDTO<String> addDepartment(@Valid @RequestBody DepartmentCreateDTO departmentCreateDTO) {
return departmentService.addDepartment(departmentCreateDTO);
}
```
5只能在 `controller` 层获取当前请求用户,并传递给 `service` 层。
> _因为获取当前请求用户是从 ThreadLocal 里获取取的,在 service、manager、dao 层极有可能是其他非 request 线程调用,会出现 null 的情况尽量避免_
```java
@ApiOperation("添加员工 @author yandanyang")
@PostMapping("/employee/add")
public ResponseDTO<String> addEmployee(@Valid @RequestBody EmployeeAddDTO employeeAddDTO) {
LoginTokenBO requestToken = SmartRequestTokenUtil.getRequestUser();
return employeeService.addEmployee(employeeAddDTO, requestToken);
}
```
### 3、 `service` 层规范
1合理拆分 service 文件,如果业务较大,请拆分为多个 service。
如订单业务,所有业务都写到 OrderService 中会导致文件过大,故需要进行拆分如下:
- `OrderQueryService` 订单查询业务
- `OrderCreateService` 订单新建业务
- `OrderDeliverService` 订单发货业务
- `OrderValidatorService` 订单验证业务
2谨慎处理 `@Transactional` 事务注解的使用,不要简单对 `service` 的方法添加个 `@Transactional` 注解就觉得万事大吉了。应当合并对数据库的操作,尽量减少添加了`@Transactional`方法内的业务逻辑。
`@Transactional` 注解内的 `rollbackFor` 值必须使用异常的基类 `Throwable.class`
> _对于@Transactional 注解,当 spring 遇到该注解时,会自动从数据库连接池中获取 connection并开启事务然后绑定到 ThreadLocal 上,如果业务并没有进入到最终的 操作数据库环节,那么就没有必要获取连接并开启事务,应该直接将 connection 返回给数据库连接池供其他使用比较难以讲解清楚如果不懂的话就主动去问。_
反例:
```java
@Transactional(rollbackFor = Throwable.class)
public ResponseDTO<String> upOrDown(Long departmentId, Long swapId) {
// 验证 1
DepartmentEntity departmentEntity = departmentDao.selectById(departmentId);
if (departmentEntity == null) {
return ResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS);
}
// 验证 2
DepartmentEntity swapEntity = departmentDao.selectById(swapId);
if (swapEntity == null) {
return ResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS);
}
// 验证 3
Long count = employeeDao.countByDepartmentId(departmentId)
if (count != null && count > 0) {
return ResponseDTO.wrap(DepartmentResponseCodeConst.EXIST_EMPLOYEE);
}
// 操作数据库 4
Long departmentSort = departmentEntity.getSort();
departmentEntity.setSort(swapEntity.getSort());
departmentDao.updateById(departmentEntity);
swapEntity.setSort(departmentSort);
departmentDao.updateById(swapEntity);
return ResponseDTO.succ();
}
```
以上代码前三步都是使用 connection 进行验证操作,由于方法上有@Transactional 注解,所以这三个验证都是使用的同一个 connection。
若对于复杂业务、复杂的验证逻辑,会导致整个验证过程始终占用该 connection 连接占用时间可能会很长直至方法结束connection 才会交还给数据库连接池。
对于复杂业务的不可预计的情况,长时间占用同一个 connection 连接不是好的事情,应该尽量缩短占用时间。
正例:
```java
DepartmentService.java
public ResponseDTO<String> upOrDown(Long departmentId, Long swapId) {
DepartmentEntity departmentEntity = departmentDao.selectById(departmentId);
if (departmentEntity == null) {
return ResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS);
}
DepartmentEntity swapEntity = departmentDao.selectById(swapId);
if (swapEntity == null) {
return ResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS);
}
Long count = employeeDao.countByDepartmentId(departmentId)
if (count != null && count > 0) {
return ResponseDTO.wrap(DepartmentResponseCodeConst.EXIST_EMPLOYEE);
}
departmentManager.upOrDown(departmentSort,swapEntity);
return ResponseDTO.succ();
}
DepartmentManager.java
@Transactional(rollbackFor = Throwable.class)
public void upOrDown(DepartmentEntity departmentEntity ,DepartmentEntity swapEntity){
Long departmentSort = departmentEntity.getSort();
departmentEntity.setSort(swapEntity.getSort());
departmentDao.updateById(departmentEntity);
swapEntity.setSort(departmentSort);
departmentDao.updateById(swapEntity);
}
```
将数据在 service 层准备好,然后传递给 manager 层,由 manager 层添加@Transactional 进行数据库操作。
3需要注意的是注解 `@Transactional` 事务在类的内部方法调用是不会生效的
反例如果发生异常saveData方法上的事务注解并不会起作用
```java
@Service
public class OrderService{
public void createOrder(OrderCreateDTO createDTO){
this.saveData(createDTO);
}
@Transactional(rollbackFor = Throwable.class)
public void saveData(OrderCreateDTO createDTO){
orderDao.insert(createDTO);
}
}
```
> _Spring采用动态代理(AOP)实现对bean的管理和切片它为我们的每个class生成一个代理对象。只有在代理对象之间进行调用时可以触发切面逻辑。而在同一个class中方法A调用方法B调用的是原对象的方法而不通过代理对象。所以Spring无法拦截到这次调用也就无法通过注解保证事务了。简单来说在同一个类中的方法调用不会被方法拦截器拦截到因此事务不会起作用。_
解决方案:
1. 可以将方法放入另一个类,如新增 `manager层`通过spring注入这样符合了在对象之间调用的条件。
2. 启动类添加` @EnableAspectJAutoProxy(exposeProxy = true)`,方法内使用` AopContext.currentProxy() `获得代理类,使用事务。
```java
SpringBootApplication.java
@EnableAspectJAutoProxy(exposeProxy = true)
@SpringBootApplication
public class SpringBootApplication {}
OrderService.java
public void createOrder(OrderCreateDTO createDTO){
OrderService orderService = (OrderService)AopContext.currentProxy();
orderService.saveData(createDTO);
}
```
4service是具体的业务处理逻辑服务层尽量避免将web层某些参数传递到service中。
反例:
```java
public ResponseDTO<String> handlePinganRequest(HttpServletRequest request){
InputStreamReader inputStreamReader = new InputStreamReader(request.getInputStream(), "GBK");
BufferedReader reader = new BufferedReader(inputStreamReader);
StringBuilder sb = new StringBuilder();
String str;
while ((str = reader.readLine()) != null) {
sb.append(str);
}
if(!JSON.isValid(msg)){
return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM);
}
PinganMsgDTO PinganMsgDTO = JSON.parseObject(msg,PinganMsgDTO.class);
// 示例结束
}
```
反例中出现的问题:
- 反例中把 `HttpServletRequest` 传递到service中是为了获取Request流中的字符信息然后才是真正的业务处理。按照分层的初衷将代码、业务逻辑解耦正确的做法应该是`handlePinganRequest`方法将`String`字符作为参数直接处理业务,将从`Request`中获取字符的操作放入`controller`中。
- 另一个坏处是不方便做单元测试,还得一个`new`一个`HttpServletRequest`并制造一个`InputStream`,然而这样做并不能模拟到真实的业务情景及数据。
### 4、 manager 层规范
manager 层的作用(引自《阿里 java 手册》)
- 对第三方平台封装的层,预处理返回结果及转化异常信息;
- 对 Service 层通用能力的下沉,如缓存方案、中间件通用处理;
- 与 DAO 层交互,对多个 DAO 的组合复用。
### 5、 dao 层规范
优先使用 mybatis-plus 框架。如果需要多个数据源操作的,可以选择使用 SmartDb 框架。
1所有 Dao 继承自 BaseMapper
2禁止使用 Mybatis-plus 的 Wrapper 条件构建器
3禁止直接在 mybatis xml 中写死常量,应从 dao 中传入到 xml 中
3建议不要使用星号 `*` 代替所有字段
正例:
```xml
NoticeDao.java
Integer noticeCount(@Param("sendStatus") Integer sendStatus);
---------------------------------------------
NoticeMapper.xml
<select id="noticeCount" resultType="integer">
select
count(1)
from t_notice
where
send_status = #{sendStatus}
</select>
```
反例:
```xml
NoticeDao.java
Integer noticeCount();
---------------------------------------------
NoticeMapper.xml
<select id="noticeCount" resultType="integer">
select
count(1)
from t_notice
where
send_status = 0
</select>
```
3dao层方法命名规范
- 获取单个对象的方法用 `get` 做前缀。
- 获取多个对象的方法用 `list` 做前缀。
- 获取统计值的方法用 `count` 做前缀。
- 插入的方法用 `save/insert` 做前缀。
- 删除的方法用 `remove/delete` 做前缀。
- 修改的方法用 `update` 做前缀。
建议dao层方法命名尽量以sql语义命名避免与业务关联。
正例:
```java
List<PerformanceDTO> listByMonthAndItemId(@Param("month") String month, @Param("itemId") Integer itemId);
```
反例:
```java
List<PerformanceDTO> getInternalData(@Param("month") String month, @Param("itemId") Integer itemId);
```
反例中出现的不规范操作:
- get代表单个查询批量查询的应该 list 开头。
- 命名与业务关联局限了dao方法的使用场景和范围降低了方法的复用性造成他人困惑以及重复造轮子。
### 6、boolean类型的属性命名规范
> 类中布尔类型的变量都不要加is否则部分框架解析会引起序列化错误。反例定义为基本数据类型 Boolean isDeleted的属性它的方法也是 isDeleted()RPC在反向解析的时候“以为”对应的属性名称是 deleted导致属性获取不到进而抛出异常。
这是阿里巴巴开发手册中的原文,我们团队的规定是:`boolean` 类型的类属性和数据表字段都统一使用 `flag` 结尾。虽然使用 `isDeletedis_deleted` 从字面语义上更直观,但是比起可能出现的潜在错误,这点牺牲还是值得的。
正例:
```
deletedFlagdeleted_flagonlineFlagonline_flag
```
### 7、
## 四、数据库 规范
### 1 建表规范
表必备三字段id, create_time, update_time
- id 字段 Long 类型,单表自增,自增长度为 1
- create_time 字段 datetime 类型,默认值 CURRENT_TIMESTAMP
- update_time 字段 datetime 类型,默认值 CURRENT_TIMESTAMP, On update CURRENT_TIMESTAMP
### 2 枚举类表字段注释需要将所有枚举含义进行注释
修改或增加字段的状态描述,必须要及时同步更新注释。
如下表的 `sync_status` 字段 `同步状态 0 未开始 1同步中 2同步成功 3失败`
正例:
```sql
CREATE TABLE `t_change_data` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`sync_status` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' COMMENT '同步状态 0 未开始 1同步中 2同步成功 3失败',
`sync_time` DATETIME NULL DEFAULT NULL COMMENT '同步时间',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`change_data_id`)
)
```
反例:
```sql
CREATE TABLE `t_change_data` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`sync_status` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' COMMENT '同步状态 ',
`sync_time` DATETIME NULL DEFAULT NULL COMMENT '同步时间',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`change_data_id`)
)
```
### 3 合理结合业务给表字段添加索引和唯一索引
具体索引规范请参照《阿里巴巴 Java 开发手册》索引规约
## 五、其他
### 1、代码提交规范
- 提交前应该冷静、仔细检查一下,确保没有忘记加入版本控制或不应该提交的文件。
- 提交前应该先编译一次idea里ctrl+F9防止出现编译都报错的情况。
- 提交前先更新pull一次代码提交前发生冲突要比提交后发生冲突容易解决的多。
- 提交前检查代码是否格式化,是否符合代码规范,无用的包引入、变量是否清除等等。
- 提交时检查注释是否准确简洁的表达出了本次提交的内容。
### 2、maven项目
- pom禁止出现相同 groupIdartifactId 的依赖配置。
- 项目名称应该与 artifactId 保持一致。
- 定期检查jar包依赖关系及时排除解决冲突的jar包。
### 3、保持项目整洁
使用git必须添加 .gitignore 忽略配置文件。
不要提交与项目无关的内容文件idea配置、target包等。