Commit 18d99c9c authored by chen.tao's avatar chen.tao

init

parents
Pipeline #79 failed with stages
# RESTful 接口开发规范
版本:v1.0
时间:2019-01-28
[TOC]
## REST概念
REST是Representational State Transfer的英文缩写,翻译成中文是"表述性状态转移"。具体含义下一章节会做详细解释
REST是一种软件架构风格,不是一种标准,它提供一组设计原则和约束条件,满足这些设计原则和约束条件的架构设计就是RESTful架构风格
## RESTful Architectural Style
### RESTful架构风格特点
- 资源
- URI
- 统一接口
- 无状态
**资源**
资源就是网络上的一个实体,可以是一个对象,也可以是一种关系。资源需要通过某种载体来表现其内容,例如:图片可以用JPG格式表现,也可以用PNG格式表现,而JSON数据格式是现在最常用的资源表现形式。
**URI(统一资源定位符)**
每一个资源可以用一个特定的URI指向它,要获取这个资源,访问它的URI就可以,因此URI成了每一个资源的独一无二的地址或识别符。
**统一接口**
数据的元操作,即CRUD(create、 read、 update、delete),分别基于HTTP方法:POST,GET,PUT,DELETE统一了数据操作的接口,仅通过HTTP方法,就可以完成对数据的所有操作
**无状态**
状态应该区分应用状态和资源状态,客户端负责应用状态,服务端负责资源状态。客户端与服务端的交互是无状态的,在每一次请求中包含处理该请求所需的一切信息。服务端不需要在请求间保留应用状态。这种无状态通信原则,使得在多次请求中,同一客户端不再需要依赖于同一服务器,可实现高可扩展和高可用性的服务端。
回过头来,再来理解一下REST的定义"表述性状态转移",其实它忽略了一个主语"资源" - 资源表述性状态转移。因此结合RESTful架构风格的特点,可以理解REST就是:我们可以通过URI来唯一的定位一个资源,资源通过例如JSON对象来表示,当发生前后端无状态交互时,通过HTTP的GET,POST,PUT,DELETE方法对应create、 read、 update、delete来修改资源的状态。
### RESTful架构风格优势
java几种典型的软件架构
- 分布式对象(Distributed Objects,简称DO)
架构实例有CORBA/RMI/EJB/DCOM, 面向对象,语言相关,客户端服务器紧耦合,API接口不统一
- 远程过程调用(Remote Procedure Call,简称RPC)
架构实例有SOAP/XML-RPC/DWR,面向过程,语言相关,客户端服务器紧耦合,API接口不统一
- 表述性状态转移(Representational State Transfer,简称REST)
架构实例有HTTP/WebDAV,面向资源,语言无关,客户端服务器松耦合,API接口统一
当今的软件开发过程中,往往需要与许多外部系统集成或者调用众多外部服务,REST这种与开发语言无关,仅仅基于HTTP的统一接口就能完成数据交互的特点,再加之客户端服务器松耦合,无疑带来了巨大的便利以及开发效率的提升。
## RESTful API开发规范
### API设计的基本准则
- 当准则合理,且满足条件时,遵守准则
- API应该面向资源定义
- API应该保证GET,PUT,POST,DELETE分别对应query,update,create,delete操作
- API应该对程序员友好,并且在浏览器地址栏容易输入
- API应该简单,直观,容易使用,并且尽量保证优雅
- API应该具有足够的灵活性来支持前端业务需求
```
说明一点:API的就是程序员的UI,和其他UI一样,必须仔细考虑它的用户体验!!!
```
### RESTful API设计和开发细则
下面将详细列出一些RESTful API的设计和开发规范:
1. 文档
```
文档和API一样重要,前期RESTful API文档插件调研,以选择apiggs作为内部RESTful API文档生成器,具体使用方法和文档模板,请参考
forever-play > resourcers 下面的 《Apiggs RESTful API文档生成工具使用指南》。
最终所有API的接口文档必须生成放在项目指定apiDocs目录
```
2. **使用https协议**
```
使用https安全,如果不使用https,请使用其他安全方案,比如使用token等其他认证方案。
```
3. **版本号放入URL**
```
在API上加入版本信息可以有效的防止用户访问已经更新的API,同时也能让不同主要版本之间平稳过渡
get api/v1/users/good 获得用户列表
v表示版本 1版本号.URL中不使用1.1带小版本的子版本号,如果需要放入HEAD中
```
4. **请求头公共参数**
```
每个请求公有的参数,比如token、请求客户端类型、请求来源(前台展示还是后台管理);
公共参数放在请求header中:
请求头参数|是否必须 | 说明
|---|---|---|
|x-app | 是 | 客户端类型:*-ios,*-android,*-pc,*-h5|
|x-lang | 是 | 客户端语言:'en-us','zh-cn'等,默认中文|
|x-orginal | 是 | 请求来源:0-前台展示调用,默认;1-后台管理|
|x-token | 是 | 认证凭证|
其他,后续根据实际情况添加.
```
5. **只提供json返回格式(其实不仅仅返回json)**
```
对于响应返回的格式,JSON 因为它的可读性、紧凑性以及多种语言支持等优点,成为了 HTTP API 最常用的返回格式,因此采用JSON 作为返回内容的格式。如果用户需要其他格式,比如xml,应该在请求头部 Accept 中指定。
对于不支持的格式,服务端需要返回正确的status code,并给出详细的说明。
Accept:application/json 告诉服务器客户端接受JSON格式返回
Content-Type:application/json 告诉服务器请求内容为JSON格式
```
6. **使用自定义错误编码**(~~使用http状态码作为错误提示~~)
```
使用http状态码作为错误提示是符合rest接口规范。
业界现在有两种做法:
1. 使用http状态码
比如:
200 请求成功接收并处理,一般响应中都会有 body
404 客户端要访问的资源不存在,链接失效或者客户端伪造 URL 的时候回遇到这个情况
...
2. 使用自定义返回的错误码
比如:
1000 系统错误
2001 用户不存在
2002 用户名称已经存在
...
建议使用自定义的状态。
原因:
http状态码可能不够用(暂时肯定够);
使用自定义返回的错误码更加灵活;
便于后台代码统一处理;
推荐而已;
```
7. **URI Path尽量使用名词,不使用动词,把每个URL看成一个资源**
```
get /getUserList // bad 获得所有用户列表
get /getActiveUserList //bad 获得所有激活的用户列表
get /api/v1/users // good 获得所有用户列表
get /api/v1/users?state=active // good 获得所有激活的用户列表
rest只是一种接口规范不是标准.尽量遵守即可.有的接口不好用名词描述或者描述会让人很难理解,特殊情况我们还是可以使用动词进行描述.
比如:登录|注销
post /api/v1/session //登录接口
delete /api/v1/session //注销接口
十分不易与理解接口的真实含义,此时用大家非常熟悉的词语,即使是动词也未尝不可,只要注意在文档中写清楚就可以了。
post /api/v1/login //登录接口
delete /api/v1/logout // 注销接口
get /api/v1/search // 搜索
请记住,应该简单,直观,容易使用,并且尽量保证优雅
```
8. **避免URI Path最后带'/'**
```
get /api/v1/users/ // bad
get /api/v1/users // good
最后带'/'与不带意思完全不一样,甚至两个不同的接口
```
9. **资源名称推荐用复数名词**
```
get /api/v1/users // good 查询用户列表
get /api/v1/users/1 // good 查询用户1的信息
get /api/v1/user // bad 查询用户列表
get /api/v1/user/1 // bad 查询用户1的信息
事实上,这是个人爱好问题,但复数形式更为常见。
此外,在资源集合URL上用GET方法,它更直观,特别是get /api/v1/users?state=active。
但最重要的是:避免复数和单数名词混合使用,这显得非常混乱且容易出错。
```
10. **为关系使用子资源**
```
多级资源命名:
get /api/v1/users/1/roles //查看用户1的角色信息
get /api/v1/roles/admin/users // 查看管理员的角色列表
如果资源层级太深,可以使用除了第一级,其他级别都用查询字符串表达。
get /api/v1/roles?users=1 //查看用户1的角色列表
get /api/v1/users?roles=admin // 查看管理员的角色列表
```
11. **使用小驼峰命名法**
```
使用小驼峰命名法作为属性标识符。
{ "yearOfBirth": 1982 }
不要使用下划线(year_of_birth)或大驼峰命名法(YearOfBirth)。
通常,RESTful Web服务将被JavaScript编写的客户端使用。
客户端会将JSON响应转换为JavaScript对象(通过调用var person = JSON.parse(response)),然后调用其属性。
因此,最好遵循JavaScript代码通用规范。
person.year_of_birth // 不推荐,违反JavaScript代码通用规范
person.YearOfBirth // 不推荐,JavaScript构造方法命名
person.yearOfBirth // 推荐
```
12. **对可选的、复杂的查询参数,使用查询字符串(?)**
```
get /activeUsers //bad
get /disableUsers //bad
为了让你的URL更小、更简洁。
为资源设置一个基本URL,将可选的、复杂的参数用查询字符串表示。
get /api/v1/users?state=active&sex=male //good
```
13. **使用HTTP动词(GET,POST,PUT,DELETE)作为action操作URL资源**
```
get 查询
post 添加
patch 修改
put 修改(PUT 是幂等的,而 PATCH 不是幂等的,一般用put就ok)
delete 删除
推荐
get /api/v1/users // good 查询用户列表
post /api/v1/users //good 添加用户
put /api/v1/users //good 编辑用户
delete /api/v1/users/1 //good 删除参数
get请求传参使用url请求参数传参
post|put请求使用body传参,json格式
delete请求使用url路径传参,如果是批量删除使用body传参,json格式
get /api/v1/users?state=active //查询激活用户列表
post /api/v1/users //添加用户
body:
{
id:1,
name:'duanledexianxian',
state:'active',
....
}
put /api/v1/users //修改用户
body:
{
id:1,
name:'duanledexianxian',
state:'active',
....
}
delete /api/v1/users/1 //删除参数 1是用户id
delete /api/v1/users //批量删除参数
or
delete /api/v1/users/batch //批量删除参数
{
ids:[1,2,....]
}
```
14. **Query Filter信息**
```
例如:
pageNum:第几页,默认0
pageSize:每页条数,默认10
sort:column1,column2排序字段
orderby:排序规则,desc或asc
q:搜索关键字(uri encode之后的)
建议将查询参数封装成QueryCondition的dto对象,通过filter放入TreadLocal中,用的时候直接从TreadLocal获取.
```
15. **返回结果**
```
1. GET:返回资源对象
2. POST:返回新生成的资源对象
3. PUT:返回完整的资源对象
4. DELETE:返回一个空文档
统一返回格式:
{
code:'SUCCESS',//成功返回'SUCCESS',否则返回自定义的错误编码
message:'错误描述信息',//如果错误,则还有错误描述信息属性字段
data:{}// 返回数据内容
}
分页查询返回结果格式
统一返回格式:
{
code:'SUCCESS',//成功返回'SUCCESS',否则返回自定义的错误编码
data:{
pageNum:0,//分页页面
pageSize:10,//分页大小
total:100,//记录总数
pages:10,//分页页数
list:[...]//列表内容
}// 返回数据内容
}
新增操作需要返回新增资源的资源唯一编号,比如:新增用户
{
code:'SUCCESS',//成功返回'SUCCESS',否则返回自定义的错误编码
data:{
id:1,//用户编号
name:'duanledexianxianxian',//用户名称
...
}// 返回数据内容
}
```
16. **速率限制(暂时不需要)**
```
1. X-RateLimit-Limit: 每个IP每个时间窗口最大请求数
2. X-RateLimit-Remaining: 当前时间窗口剩余请求数
3. X-RateLimit-Reset: 下次更新时间窗口的时间(UNIX时间戳),达到下个时间窗口时,Remaining恢复为Limit
如果对访问的次数不加控制,很可能会造成 API 被滥用,甚至被 DDos 攻击。
根据使用者不同的身份对其进行限流,可以防止这些情况,减少服务器的压力。
暂时不需要,以后做限流控制、访问控制的时候会用的上
```
17. **限制返回值的域,fields=id,subject,customerName**
```
比如:/api/v1/users?fields=id,name,....//获取用户列表,包含的字段包括id、名称.可以一起处理
```
*注意*
```
对于REST未覆盖的内容:
1. Hypermedia API(HATEOAS),通过接口URL获取接口地址及帮助文档地址信息, 暂时不需要,如果需要实现前后台都需要改动
2. 缓存,使用ETag和Last-Modified 暂时不需要,做性能优化的时候,根据需要添加
3. 文件上传,下载 *
未完待续.....
```
## Reference
1. RESTful API 设计最佳实践 <http://blog.jobbole.com/41233/>
2. RESTful Representational State Transfer 表现层状态转化 https://blog.csdn.net/flancklin/article/details/52311505
3. RESTful设计原则和样例 https://my.oschina.net/u/2330859/blog/468829
**标题 简单描述任务**
详细描述任务内容
------
cc/ @member (如果没有需要通知的成员 请删除此行)
\ No newline at end of file
**标题 简单描述文档修改建议**
文档名称 (详细名称+版本)
详细描述文档修改建议(可截图,建议分章节组织内容)
------
cc/ @member (如果没有需要通知的成员 请删除此行)
# gitlab初始化准备工作
版本:v1.0
时间:2019-01-30
[TOC]
## 创建群组
一般产品开发时,创建一个产品Group,再分别创建至少4个工程,前端工程,后端工程,文档工程,数据库脚本工程
可以在Group创建issue&merge模板和标签,可以在子工程中继承
## 创建工程
创建项目有3种访问权限
- private 完全私有的,如果要添加用户必须手工添加 **//一般产品研发项目用这种**
- internal 内部使用,这里指的是登录gitlab的用户,就是登录认证通过的
- public 完全公开 随意访问 **//公司级别内部共享的框架项目用这种**
当项目为private的时候,添加用户有几种角色
- Master
- Developer
- Reportor
- Guest //没有什么权限,代码都看不见,只能看看wiki和一些琐碎的东西
具体权限可以看这里: <http://fitnesstest.diankexuexi.com:10080/help/user/permissions>
按照权限要求,添加用户
## 创建issue&merge模板
创建步骤:
- 在根目录下创建 [.gitlab](http://fitnesstest.diankexuexi.com:10080/CT/training/tree/master/.gitlab) 目录
-[.gitlab](http://fitnesstest.diankexuexi.com:10080/CT/training/tree/master/.gitlab) 目录创建issue_templates目录和merge_request_templates目录
- issue_templates目录分别放入:feature issue templates,bug issue templates,document issue templates,test issue templates,management issue templates
- merge_request_templates目录分别放入:feature merge request templates,bug merge request templates,product merge request templates
在创建Issue时根据任务类型,选择不同的模板
![2](https://i.loli.net/2019/02/13/5c62ee49a6e9e.jpg)
## Issue初始化label
issue里面还有一个label需要配置,从任务类型,完成状态,紧急程度,几个维度描述,对于一个issue并不是所有维度标签都是必需的:**类型(必需),紧急程度(可选),完成状态(必需)**
**类型**
- feature 新功能开发任务 //#00A8DF
- bug 修复bug任务 //#FF3737
- document 文档任务 //#D1D100
- testing 测试任务 //#5CB85C
- management 管理任务 其他类型都算到这里 //#44AD8E
- MR feature 新功能分支合并 //#5843AD
- MR bug 修复bug任务 //#D10069
- MR product 文档任务 //#AD8D43
**紧急程度**
- normal 一般不紧急 可稍缓 //#00A8DF
- concerned 需要关注 尽快解决的 //#FF6D0D
- critical 非常严重 立即处理 // #FF3737
**完成状态**
- todo 准备做的 尚未开始 //#7F8C8D
- processing 正在处理 //#00A8DF
- pending 挂起 暂时挂起稍后处理 //#34495E
- acceptance 已完成 待验收 //#44AD8E
![1](https://i.loli.net/2019/02/13/5c62ee09a9b5f.jpg)
## 创建Milestones
issue里面创建Milestones,将所有Issue按照Milestones进行分组管理
## 创建Product分支
默认工程创建完成,就会有Master分支,但是按照分支开发的原则,还需要有其他分支
- master 长期分支 开发在此进行,包括持续集成
- product 长期分支 只保存里程碑版本 不对其进行开发操作
- feature & fixbug 短期分支 feature是新需求 开发人员根据feature issue开分支,fixbug是bug 开发人员根据bug issue开分支 完成后删除
创建product分支
- 直接在gitlab上进入repository >> 分支 下面直接创建product分支
- 设置分支保护,确保product分支的修改权限受控
\ No newline at end of file
**Bug描述**
<!--- 描述bug产生的模块,具体出现的问题 -->
**Bug界面呈现**
<!--- 可选 如果是前端发生的问题 可截图说明 -->
**Bug重现步骤**
<!--- Steps to reproduce 列出问题产生的详细步骤 以便于重现问题 或者 标明偶现 -->
**期望结果**
<!--- 描述无bug时正常的结果 可映射 测试案例文档,需求文档或设计文档 -->
**操作日志**
<!--- 可选 问题可定位 直接贴日志(内容少)无法定位或内容多 以附件方式提供 -->
------
cc/ @member (如果没有需要通知的成员 请删除此行)
**文档名称**
<!--- 文档名称 -->
**文档描述**
<!--- 概要描述文档作用和内容 -->
**文档要求**
<!--- 可选 对文档编写的具体要求 -->
------
cc/ @member (如果没有需要通知的成员 请删除此行)
**功能描述**
<!--- 概要描述需求 -->
**实现要求**
<!--- 可选 交互性,性能等实现要求 -->
**文档映射**
<!--- 可选 对应需求,设计文档及其章节 -->
------
cc/ @member (如果没有需要通知的成员 请删除此行)
**管理事务描述**
<!--- 概要描述管理事务的具体内容 -->
**目标&要求**
<!--- 可选 对管理事务执行的目标和要求 -->
------
cc/ @member (如果没有需要通知的成员 请删除此行)
**测试计划**
<!--- 描述测试范围,测试内容 -->
**测试案例**
<!--- 可选 测试案例映射关系 -->
**测试要求**
<!--- 通过测试的标准 -->
------
cc/ @member (如果没有需要通知的成员 请删除此行)
**Merge Request描述**
<!--- 描述此次Merge Request的目的和作用 -->
**Bug类型**
<!--- Code || SQL -->
**Bug Issue映射**
<!--- 对应的Issue编码 & title -->
**涉及文件**
<!--- 可选 此次Merge中新建或者修改的文件列表 -->
------
cc/ @member (如果没有需要通知的成员 请删除此行)
**Merge Request描述**
<!--- 描述此次Merge Request的目的和作用 -->
**Feature类型**
<!--- Code || SQL -->
**Feature Issue映射**
<!--- 对应的Issue编码 & title -->
**涉及文件**
<!--- 可选 此次Merge中新建或者修改的文件列表 -->
------
cc/ @member (如果没有需要通知的成员 请删除此行)
**Merge Request描述**
<!--- 描述此次Merge Request的目的和作用 -->
**Milestone版本**
<!--- 描述合并后产生的里程碑版本 --->
<!--- Milestone vx.y x表示里程碑编号,y代表一个里程碑里面进行的小集中发布编号 -->
**Milestone功能列表**
<!--- 此次Milestone包含的功能列表 可直接编写也可以粘贴附件 -->
------
cc/ @member (如果没有需要通知的成员 请删除此行)
# Git开发流程规范
版本:v1.0
时间:2019-01-30
[TOC]
## 概述
### Git
Git是一个版本控制系统,与SVN,CVS这些集中式版本控制系统(Centralized Version Control System)不同,Git是一个分布式版本控制系统(Distributed Version Control System),而且可以说Git是目前世界上最先进的分布式版本控制系统。
Git与SVN,CVS相比较,其显著特点为:
- 快速
- 设计简单
- 支持上万并行开发的非线性开发模式
- 完全分布式
- 有能力高效管理超大规模项目
- 无集中式单点问题可快速恢复
至于GIt为什么具有如此神奇的能力,以及GIt具体如何使用,请参考resources目录下的《progit_v2.1.16》文档
### Gitlab
Gitlab与GitHub一样,是一个用于仓库管理系统的项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务。区别在于Gitlab是完全免费的开源项目,而且可以根据需要在内网自行搭建,是企业内部进行版本管理的首选应用工具。
### Gitlab flow
基于Git的分支管理技术,可以演化出很多涉及:版本开发,版本测试,版本迭代,版本发布和Bug修复的工作流,工作流不涉及任何命令,因为它就是一个规则,完全由开发者定义并遵守,其中比较流行的最佳实践包括:
- Git Flow
- Github Flow
- Gitlab Flow
- Trunk-Based Development
这些基于Git的工作流最佳实践无所谓好坏,只有是否满足和适合当前的场景需要。
产品研发类项目与互联网在线项目和SaaS应用服务项目在需求迭代,开发实效,功能发布等方面存在区别,例如:
- 开发周期相对较长,中间一般会有里程碑
- 产品需求相对固定,不存在频繁变更
- 单一功能需要开发在时间上要求不十分紧急
- 业务模块进行分模块开发,人员之间的业务交叠不大
- 产品一般在功能全部具备时才发布现场使用
对于产品研发类项目采用Github Flow这种面向开源项目的工作流太过简单,Trunk-Based Development这种非feature分支开发方式不利于任务分配和跟踪,Git Flow这种面向版本的流程虽然满足需要但是太过复杂。而且个人以为这些流程大多都是面向互联网项目的最佳实践。综合分析最终选择Gitlab flow的Production branch with GitLab flow方式,并结合任务管理,持续集成形成满足我们当前需要的产品研发工作流。
GitLab工作流十分年轻,2014 年 9月 29 正式发布。由于出现比Git FLow和GitHub FLow晚,因此它集百家之长,补百家之短。GitLab 既支持 Git Flow 的分支策略,也有类似 GitHub Flow 的 Pull Request和 issue tracking,这些对于产品研发类项目都是极好的能力
## 开发流程
### 流程视图
以下为完整的git开发流程![](https://i.loli.net/2019/02/07/5c5c32ce8cda2.jpg)
1. 在gitlab创建仓库,创建master分支和product分支,master分支初始代码为开发需要的框架代码
2. 需求分解,获得feature,粒度3天,使用gitlab的issue对feature进行管理,标记feature标签,命名以Feature_简单描述
3. feature开发时从master分支拉feature分支进行开发,开发完成后,本地完成测试,确保代码无误后,提交Merge request
4. 在进行代码审核通过后,feature分支合并到master分支,触发持续集成(自动编译,代码静态检查,单元测试),成功后发布到持续集成开发环境,删除feature分支
5. 创建每日集成,每日定时将master分支代码进行自动化集成,完成后发布到每日集成开发环境
6. 待一个里程碑feature开发完成后,发起里程碑计划,手动触发集成部署到测试环境
7. 测试环境产生的bug录入fixbug issue在issue进行管理,开发人员从master分支拉取fixbug分支进行bug修复(过程类似feature branch)
8. 当里程碑测试完成后,product分支与master分支进行merge,在product上产生里程碑版本,并tag为milestone_vx.x
9. 以上过程随里程碑不断迭代推进,直到产品全部完成, product上将产生最后的产品发布版本
### 基本准则
1. **使用Feature分支,不直接提交到Master分支**
```
当开发一个新的功能或者修改bug时,应该创建一个分支进行开发或修复,完成后提交Merge Request,而不要直接基于Master分支进行任何开发。
```
2. **测试所有的提交,不仅仅是Master分支上的提交,在所有的提交上运行所有的测试**
```
持续集成如果仅仅是测试那些被合并到master的提交是不够的,对于master应该总是保持测试结果均为绿色,也就是说持续集成是应该是重新做一次完整的自动化测试,包括之前已提交的模块。
```
3. **及早提交Feature分支到Master分支,并且在合并到Master分支前执行代码评审**
```
为了发挥持续集成的作用“尽早集成,尽早发现和解决问题”,Feature分支开发完成应该尽早的提交Merge Request,理论上一个Feature的开发时间尽量不要超过3天,如果超过,拆分Feature,千万不要在一周结束的时候才提交所有内容。
提交Merge Request后,尽可能的落地代码走查和评审,特别是对于经验尚浅的开发人员,提交Merge Request时必须cc开发经理和相关开发人员完成代码走查和评审
```
4. **基于Master分支进行持续集成,并实现开发环境的自动化部署**
```
在Master分支部署持续集成流程,当Feature分支Merge到Master分支时进行自动化构建,单元测试和其他代码检查,通过后自动将代码发布到开发环境(实时更新)。另外,考虑到变更如果频繁会影响基于开发环境的调试,建议创建一个每日定时构建的开发环境,同样自动化部署
```
5. **基于Milestone创建里程碑版本,手动创建里程碑测试环境**
```
产品研发的里程碑要创建里程碑版本,以确保在一个阶段结束时,当前软件版本可用,测试在此环节介入,手动从Master分支部署测试环境进行集成测试,注意里程碑版本不对外发布,只属于研发内部流程中
```
6. **依赖tags版本进行发布**
```
Milestone里程碑版本测试完成后,将Product分支与Master分支Merge,并通过tag(Milestone_vX.X),基于Product分支发布里程碑版本,Product分支就是里程碑版本分支,永远记录当前最新里程碑版本的内容,记住不要直接对其进行任何操作,除了Merge,tag
```
7. **绝不以重置方式提交变更**
```
禁止使用 git rebase, 代码应该纯净,修改历史应该真实。
```
8. **每个人都应该从Master分支开始,并一直以Master分支为基础**
```
不从任何分支开始,只从Master分支创建Feature分支,提交Merge Request将Feature合并到Master
```
9. **先修改Master分支中的错误,之后发布其他分支**
```
修改Bug应该先从Master分支创建FixBug分支修改问题,之后将其Merge到Master分支,如果这个bug影响到之前的发布版本可以 cherry-pick到其他分支(目前在开发流程上控制一个里程碑完成之前所有bug只用在master分支修复即可,里程碑版本允许存在少数bug,只需在下一个里程碑修复即可)。
```
10. **提交的信息中详细描述意图.**
```
在一次Commit和Merge时应该详细描述做了什么,甚至为什么这么做。清楚的表明此次Commit和Merge的意图
```
11. **持续集成过程中出现的问题,优先级最高.**
```
持续集成中出现的问题,优先级最高,需要立即解决(提交者或者关系人)或者回滚(开发经理),在merge代码到master进行持续集成的过程中,请等待持续集成成功再做后续事情,一旦持续集成环境出现错误,原则上不允许继续merge代码到master
```
12. **分支合并需本地先验证.**
```
feature分支和fixbug分支合并master分支时,需要在本地先merge再提交master合并
1:进入master,更新master代码 git pull;
2:切换分支 git checkout branch;
3:在分支上合并主干 git merge master --squash
4:提交合并后的代码 git commit -m ‘合并备注’
5:将代码推送到远程仓库 git push
```
### 任务管理
需求和Bug均以Issue的方式进行跟踪和管理
- 需求分析完成后,进行需求分解,理论上预估完成时间不超过3天
- 分解后的需求通过issue进行管理,赋予feature标记,issue以Feature+下划线+需求名称命名
- fixBug作为特殊任务也通过issue进行管理,bug赋予bug标记,issue以Bug+下划线+bug名称命名
- issue归属于一个里程碑
- issue完成后修改issue完成状态
### 分支管理
完整流程中包括master分支,product分支,feature分支,fixbug分支,其中master和product分支是长周期分支,feature和fixbug分支是短分支,在完成合并后删除。
- product分支保存最新可用的里程碑版本,直至最终的产品发布版本,product分支不允许直接修改
- 开发均在master分支,master分支是所有开发的起点,包括拉feature分支,fixbug分支也是源于master分支
- feature分支,fixbug分支开发完成必须在本地测试通过,以及在本地完成merge后再提交到master分支merge
### 持续集成
- 每次在有分支成功合并到master分支时自动进行持续集成,完成代码编译,代码检查,单元测试,测试报告,满足要求通过后发布到持续集成开发环境
- 每日定时从master分支进行集成,完成代码编译,代码检查,单元测试,测试报告,满足要求通过后将代码发布到每日集成开发环境
### 版本命名
软件版本号有四部分组成,第一部分为主版本号,第二部分为次版本号,第三部分为修订版
本号,第四部分为日期版本号加希腊字母版本号,希腊字母版本号共有五种,分别为base、alpha、beta 、RC 、 release
例如: product 1.10.1.20190215_release
```
Base:此版本表示该软件仅仅是一个假页面链接,通常包括所有的功能和页面布局,但是页面中的功能都没有做完整的实现,只是做为整体网站的一个基础架构。
Alpha :软件的初级版本,表示该软件在此阶段以实现软件功能为主,通常只在软件开发者内部交流,一般而言,该版本软件的Bug较多,需要继续修改,是测试版本。测试人员提交Bug经开发人员修改确认之后,发布到测试网址让测试人员测试,此时可将软件版本标注为alpha版。
Beta :该版本相对于Alpha 版已经有了很大的进步,消除了严重错误,但还需要经过多次测试来进一步消除,此版本主要的修改对象是软件的UI。修改的的Bug 经测试人员测试确认后可发布到外网上,此时可将软件版本标注为 beta版。
RC :该版本已经相当成熟了,基本上不存在导致错误的Bug,与即将发行的正式版本相差无几。
Release:该版本意味“最终版本”,在前面版本的一系列测试版之后,终归会有一个正式的版本,是最终交付用户使用的一个版本。该版本有时也称标准版。
```
```
主版本号:当功能模块有较大的变动,比如增加模块或是整体架构发生变化。此版本号由项目决定是否修改。
次版本号:相对于主版本号而言,次版本号的升级对应的只是局部的变动,但该局部的变动造成程序和以前版本不能兼容,或者对该程序以前的协作关系产生 了破坏,或者 是功能上有大的改进或增强。此版本号由项目决定是否修改。
修订版本号:一般是Bug 的修复或是一些小的变动或是一些功能的扩充,要经常发布修订版,修复一个严重 Bug 即可发布一个修订版。此版本号由项目经理 决定是否修改。
日期版本号:用于记录修改项目的当前日期,每天对项目的修改都需要更改日期版本号。此版本号由开发人员决定是否修改。
希腊字母版本号:此版本号用于标注当前版本的软件处于哪个开发阶段,当软件进入到另一个阶段时需要修改此版本号。此版本号由项目决定是否修改。
```
## 参考资料
1. progit_v2.1.16.pdf
2. 持续集成与 Git 工作流 <https://xiaozhuanlan.com/topic/9423856710>
3. 推荐的源码管理策略-gitlab flow <https://blog.csdn.net/xiaosongluo/article/details/86675493>
4. Introduction to GitLab Flow https://docs.gitlab.com/ee/workflow/gitlab_flow.html
5. The 11 Rules of GitLab Flow https://about.gitlab.com/2016/07/27/the-11-rules-of-gitlab-flow/
\ No newline at end of file
# Git使用规范
版本:v1.0
时间:2019-02-12
[TOC]
### 一、创建``Issues``
PM在gitlab创建Issue,分配给开发人员
![](https://raw.githubusercontent.com/changshawulin/pic/master/img/20190213141359.png)
### 二、获取主干最新代码
开发人员领取到人物之后,每次开发新功能之前,都必须要获取主干最新代码。
```
# 获取主干最新代码
$ git checkout master
$ git pull
```
![](https://raw.githubusercontent.com/changshawulin/pic/master/img/20190213172204.png)
### 三、新建分支
开发人员领取到任务之后,每次开发新功能,都应该新建分支,分支命名以``feature````fix``开始。
```
# 新建一个开发分支myfeature
$ git checkout -b myfeature
```
![](https://raw.githubusercontent.com/changshawulin/pic/master/img/20190213141558.png)
**``Notes``分支命名规范**
- 功能性分支
``feature/{$username}/{$version}/{$date}/{$issue_id}_{$description}``
其中:
feature 使用单数;
变量 $username 代表开发者。username 统一使用姓名首字母小写,比如 oyboy,hk;
变量 $version 代表里程碑版本号,格式为 releasex.x.x(x为数字),比如 release1.0.0;
变量``$date``代表分支创建日期,格式为``yyyyMMdd``,比如``20190213``
变量 $issue_id 代表 Issue ID,例如#64686;
变量 $description 代表分支功能描述。应该尽量用简短的词组描述,建议使用中文,多个单词用下划线分割,比如 remove_thread。
完整的例子:
``feature/hk/release1.0.0/20190213/#64686_course_conf``
- 修复分支
``bugfix/{$username}/{$date}/{aone}_{$issue_id}_{$description}``
其中:
bugfix 使用单数;
变量 $username 代表开发者。username 统一使用姓名首字母小写,比如 oyboy,hk;
变量``$date``代表分支创建日期,格式为``yyyyMMdd``,比如``20190213``
``aone``代表缺陷来源,如果为``aone``,则代表缺陷来源为Aone,否则不需要加这一项。
变量 $issue_id 代表Issue ID或者Aone缺陷ID,或者 #64686;
变量 $description 代表分支功能描述。应该尽量用简短的词组描述,建议不要使用中文,多个单词用下划线分割,比如 remove_thread。
完整的例子:
``bugfix/hk/20190213/aone_#64686_login``
````bugfix/hk/20190213/#64686_login````
### 四、与主干分支同步
在开发过程当中,要经常与主干分支保持同步,在提交``feature``代码之前,也需要先同步主干分支代码。
```
$git pull origin master
```
![](https://raw.githubusercontent.com/changshawulin/pic/master/img/20190213194004.png)
### 五、提交``commit``
```
git add -a
git commit
```
![](https://raw.githubusercontent.com/changshawulin/pic/master/img/20190213141812.png)
### 六、撰写提交信息
提交``commit``时,需要撰写完整的提交信息
```
feat:新功能(feature)
fix:修补bug
docs:文档(documentation)
style: 格式(不影响代码运行的变动)
refactor:重构(即不是新增功能,也不是修改bug的代码变动)
test:增加测试
chore:构建过程或辅助工具的变动
(详见《开发工具和插件使用指南》``Git``插件部分)
```
![](https://raw.githubusercontent.com/changshawulin/pic/master/img/20190213141900.png)
### 七、推送到远程仓库
```
$ git push origin myfeature
```
![](https://raw.githubusercontent.com/changshawulin/pic/master/img/20190213142034.png)
### 八、发出``Merge Request``
将代码推送到远程仓库后,就可以发出``Merge Request``到``master``分支,请求别人进行代码review,将代码合并进``master``分支了,可在这一步选择接受之后是否删除原分支。
![](https://raw.githubusercontent.com/changshawulin/pic/master/img/20190213142136.png)
![](https://raw.githubusercontent.com/changshawulin/pic/master/img/20190213142223.png)
### 九、合并到主分支
PM在gitlab上查看提交和代码修改情况,确认无误后,确认将开发人员的分支合并到主分支(master),接受的时候可以选择是否删除原开发分支。
![1550039002736](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1550039002736.png)
### 十、关闭``Issue``
开发人员在gitlab上添加评论并确认开发完成,并关闭issue。
**Notes**
关闭Issue两种方式
- 直接关闭
![close issue - button](https://docs.gitlab.com/ee/user/project/issues/img/button_close_issue.png)
- 通过``Merge Request``关闭
通过在``Merge Request``中(title或描述信息中)添加关键字+Issue编号,可以直接在``MR``被接受之后自动关闭,例如
```
Closes #333, #444, #555 and #666
Closes #333, #444, and https://gitlab.com/<username>/<projectname>/issues/<xxx>
```
其他下面的关键字也可以达到相同效果:
1、Close, Closes, Closed, Closing, close, closes, closed, closing
2、Fix, Fixes, Fixed, Fixing, fix, fixes, fixed, fixing
3、Resolve, Resolves, Resolved, Resolving, resolve, resolves, resolved, resolving
-----------
### 参考资料
1、阿里Git使用规范 https://yuque.antfin-inc.com/docs/share/044ce229-b5c2-47f7-803a-544ff683cb26
2、阿里``Git commit``规范 https://yuque.antfin-inc.com/tianchiplatform/ar9o6m/ql2i4g
3、Gitlab Issue https://docs.gitlab.com/ee/user/project/issues/index.html
4、``Closing Issues`` https://docs.gitlab.com/ee/user/project/issues/closing_issues.html
5、push Git自动修复Aone中录入的缺陷: https://yuque.antfin-inc.com/aone/platform/bl0h8r
6、生成Gitlab机器人(钉钉)
​ https://www.jianshu.com/p/ad6dad6f625f
​ https://open-doc.dingtalk.com/docs/doc.htm?spm=a219a.7629140.0.0.7M7pzQ&treeId=257&articleId=105736&docType=1#s0
This diff is collapsed.
# Java开发规范
版本:v1.0
时间:2019-01-30
[TOC]
## 概述
开发流程的规范化有利于保障开发过程的顺利进行,以及减少后期代码维护的成本和风险 。
此规范的目的是指导java开发人员以正确的姿势完成代码开发的全过程,内容包括:开发工具&插件使用,代码编写,数据库脚本维护,单元测试,文档化,代码版本管理和持续集成多个方面。
## 开发规范
### 工具&插件规范
工具&插件的规范定义了集成开发工具和必要的辅助开发插件
- 对于集成开发工具的使用不同开发人员可能存在不同的偏好,而且不同的集成开发工具在功能上可能也差不多,看起来好像没有统一的必要,但是集成开发工具的统一,能够提供一致的编程环境和交流语境,在一定程度上可以减少开发人员之间的沟通成本,避免辅助开发插件功能的不一致性,也有利于后期不同开发人员的维护
- 对于辅助开发插件可分为必要和非必要两种类型,必要辅助开发插件每个开发人员必须安装,并且必须按照指南正确使用,他们是确保代码质量和高维护性的技术手段。而非必要辅助开发插件一般是从某些方面提高开发效率的工具,在不违反开发规范和对团队开发造成不利影响的前提下,开发人员可个性化使用,也鼓励将优秀者向团队推荐,编写指南放置resources目录。本规范只涉及必要辅助开发插件的内容
**集成开发环境**
<u><强制></u> 集成开发环境(IDE)统一使用Intellij IDEA,版本2016及以上
2016及以上版本已完全集成Spring boot Initializer,Maven,Git等众多的辅助开发工具
**代码质量检查**
代码质量检查能够很大程度上保证开发人员写出满足规范要求的代码(优雅,高效,bug少)
由于此规范的代码开发规范是基于阿里巴巴Java开发规约,因此必须安装 “ali代码规约插件”,安装后可手动或实时启动代码规约检查。建议对遵守规约不太自信的朋友,开启实时检查,自信的朋友也请在完成代码编写后手动执行一次。
<u><强制></u> 所有开发人员必须安装 “ali代码规约插件”,并且在commit代码之前必须执行一次代码规约检查,以确保提交到仓库的代码满足规约要求
ali代码规约插件具体安装和使用请参考 《开发工具和插件使用指南》
**代码风格检查**
代码风格检查主要是保证开发人员编写的代码在格式上满足模板的要求,从而保证代码在可读性上语义一致,减少开发人员之间的沟通成本和后续的代码维护成本。
为了与代码规约保持统一,直接使用阿里java代码格式化模板,在Intellij中通过安装CheckStyle插件可以快速导入格式化模板文件。
<u><强制></u> 所有开发人员必须安装checkStyle插件以及阿里格式化模板文件,并且在commit代码之前必须执行一次代码格式化检查,以确保提交到仓库的代码满足格式要求,建议养成良好的习惯,在编码过程中以快捷键方式经常对代码进行format。
CheckStyle插件以及格式化模板具体安装和使用请参考 《开发工具和插件使用指南》
**代码bug检查**
安装Intellij中的Java静态分析工具FindBugs插件,帮助进一步的发现一些隐藏的bug。需要说明的是,FindBugs插件发现的bug有时请仅作为参考,因为它可能会产生误告警。
<u><强制></u> 所有开发人员必须安装FindBugs插件,并且在commit代码之前必须执行一次检查。
FindBugs插件具体安装和使用请参考 《开发工具和插件使用指南》
**代码安全性检查**
代码安全性对于开发人员来说可能是比较容易忽视的问题,在国际项目中,代码的安全性审计比较严格。
FindSecurityBugs是FindBugs的插件,通过一系列的规则发现代码中的Java安全漏洞。
<u><强制></u> 所有开发人员在安装FindBugs后,请确保FindSecurityBugs开启。
FindSecurityBugs插件具体安装和使用请参考 《开发工具和插件使用指南》
**文档化**
Java代码的文档化,采用javaDoc的标准进行编写,最终将由持续集成工具在项目和产品的doc目录生成完整的javaDoc文档
区分为RESTful接口文档(controler层)和一般Java代码文档
- Java代码文档
<u><强制></u> Intellij集成javaDoc工具,导入文档模板后,根据模板编写即可,具体安装和使用请参考 《开发工具和插件使用指南》
- RESTful接口文档
Swagger是一个比较不错的文档插件,但Swagger对代码的侵入性较强,且有单独的语法,存在一定学习过程,因此选择Apiggs插件,Apiggs插件直接使用javaDoc的语法,不存在任何多余的学习。
<u><强制></u> Intellij集成Apiggs插件工具,具体安装和使用请参考 《开发工具和插件使用指南》
**版本管理**
使用git进行版本管理
<u><强制></u> 安装git,在Intellij集成git插件中完成配置,具体安装和使用请参考 《开发工具和插件使用指南》
git的图形化管理工具,建议直接使用Intellij自带git插件工具,或者使用Tortoisegit
### 代码开发规范
<强制> Java代码开发规范具体细则参考《阿里巴巴Java开发手册》,并认真学习,重点关注以下章节:
```
编程规约
- 命名风格
- 常量定义
- 代码格式
- OOP规约
- 集合处理
- 控制语句
- 注释规约
异常日志
安全规约
```
### 数据库脚本规范
此项针对开发经理和设计师,数据库脚本必须纳入版本管理,并在项目或者产品script目录进行维护
具体参考《数据库脚本管理规范》
### 测试规范
对于Java开发人员 **当前阶段** 只关注单元测试,并编写自动化测试案例,测试工具采用testNg + mockito
<u><强制></u> 测试规范具体要求请参考《java单元测试规范》文档
建议先学习resources里面的《有效的单元测试》一文,对测试能够有更好的理解
### 文档规范
<u><强制></u> 如何编写有效的Java代码文档请参考《阿里巴巴Java开发手册》的注释规约部分
补充说明几点:
- 必须在集成工具中导入标准文档模板,并按照模板编写javaDoc
- 复杂的业务代码的关键流程分支处,详细描述处理原因和方法
- 核心业务代码,交互接口,公共模块必须写javaDoc
- 文档描述要准确,清晰,杜绝胡说八道
### 版本管理规范
使用git进行版本管理(包括代码和文档),并采用gitlab flow模式实现分支管理
<u><强制></u> git和gitlab flow具体使用和要求,请参考《git开发流程规范》
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<module name="Checker">
<!-- 检查文件是否以一个空行结束 -->
<module name="NewlineAtEndOfFile">
<property name="lineSeparator" value="lf" />
</module>
<!-- 文件长度不超过1500行 -->
<module name="FileLength">
<property name="max" value="1500"/>
</module>
<!-- 每个java文件一个语法树 -->
<module name="TreeWalker">
<!-- import检查-->
<!-- 检查是否从非法的包中导入了类 -->
<module name="IllegalImport"/>
<!-- 检查是否导入了多余的包 -->
<module name="RedundantImport"/>
<!-- 没用的import检查,比如:1.没有被用到2.重复的3.import java.lang的4.import 与该类在同一个package的 -->
<module name="UnusedImports" />
<!-- 注释检查 -->
<!-- 检查构造函数的javadoc -->
<module name="JavadocType">
<property name="allowUnknownTags" value="true"/>
<message key="javadoc.missing" value="类注释:缺少Javadoc注释。"/>
</module>
<!-- 命名检查 -->
<!-- 局部的final变量,包括catch中的参数的检查 -->
<module name="LocalFinalVariableName" />
<!-- 局部的非final型的变量,包括catch中的参数的检查 -->
<module name="LocalVariableName" />
<!-- 包名的检查(只允许小写字母),默认^[a-z]+(\.[a-zA-Z_][a-zA-Z_0-9_]*)*$ -->
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$" />
<message key="name.invalidPattern" value="包名 ''{0}'' 要符合 ''{1}''格式."/>
</module>
<!-- 仅仅是static型的变量(不包括static final型)的检查 -->
<module name="StaticVariableName" />
<!-- Class或Interface名检查,默认^[A-Z][a-zA-Z0-9]*$-->
<module name="TypeName">
<property name="severity" value="warning"/>
<message key="name.invalidPattern" value="名称 ''{0}'' 要符合 ''{1}''格式."/>
</module>
<!-- 非static型变量的检查 -->
<module name="MemberName" />
<!-- 方法名的检查 -->
<module name="MethodName" />
<!-- 方法的参数名 -->
<module name="ParameterName " />
<!-- 常量名的检查(只允许大写),默认^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$ -->
<module name="ConstantName" />
<!-- 定义检查 -->
<!-- 检查数组类型定义的样式 -->
<module name="ArrayTypeStyle"/>
<!-- 检查long型定义是否有大写的“L” -->
<module name="UpperEll"/>
<!-- 长度检查 -->
<!-- 每行不超过140个字符 -->
<module name="LineLength">
<property name="max" value="140" />
</module>
<!-- 方法不超过50行 -->
<module name="MethodLength">
<property name="tokens" value="METHOD_DEF" />
<property name="max" value="75" />
</module>
<!-- 方法的参数个数不超过5个。 并且不对构造方法进行检查-->
<module name="ParameterNumber">
<property name="max" value="5" />
<property name="ignoreOverriddenMethods" value="true"/>
<property name="tokens" value="METHOD_DEF" />
</module>
<!-- 空格检查-->
<!-- 方法名后跟左圆括号"(" -->
<module name="MethodParamPad" />
<!-- 在类型转换时,不允许左圆括号右边有空格,也不允许与右圆括号左边有空格 -->
<module name="TypecastParenPad" />
<!-- 检查在某个特定关键字之后应保留空格 -->
<module name="NoWhitespaceAfter"/>
<!-- 检查在某个特定关键字之前应保留空格 -->
<module name="NoWhitespaceBefore"/>
<!-- 操作符换行策略检查 -->
<module name="OperatorWrap"/>
<!-- 圆括号空白 -->
<module name="ParenPad"/>
<!-- 检查分隔符是否在空白之后 -->
<module name="WhitespaceAfter"/>
<!-- 检查分隔符周围是否有空白 -->
<module name="WhitespaceAround"/>
<!-- 修饰符检查 -->
<!-- 检查修饰符的顺序是否遵照java语言规范,默认public、protected、private、abstract、static、final、transient、volatile、synchronized、native、strictfp -->
<module name="ModifierOrder"/>
<!-- 检查接口和annotation中是否有多余修饰符,如接口方法不必使用public -->
<module name="RedundantModifier"/>
<!-- 代码块检查 -->
<!-- 检查是否有嵌套代码块 -->
<module name="AvoidNestedBlocks"/>
<!-- 检查是否有空代码块 -->
<module name="EmptyBlock"/>
<!-- 检查左大括号位置 -->
<module name="LeftCurly"/>
<!-- 检查代码块是否缺失{} -->
<module name="NeedBraces"/>
<!-- 检查右大括号位置 -->
<module name="RightCurly"/>
<!-- 代码检查 -->
<!-- 检查空的代码段 -->
<module name="EmptyStatement"/>
<!-- 检查在重写了equals方法后是否重写了hashCode方法 -->
<module name="EqualsHashCode"/>
<!-- 检查局部变量或参数是否隐藏了类中的变量 -->
<module name="HiddenField">
<property name="tokens" value="VARIABLE_DEF"/>
</module>
<!-- 检查子表达式中是否有赋值操作 -->
<module name="InnerAssignment"/>
<!-- 检查switch语句是否有default -->
<module name="MissingSwitchDefault"/>
<!-- 检查是否有过度复杂的布尔表达式 -->
<module name="SimplifyBooleanExpression"/>
<!-- 检查是否有过于复杂的布尔返回代码段 -->
<module name="SimplifyBooleanReturn"/>
<!-- 类设计检查 -->
<!-- 检查类是否为扩展设计l -->
<!-- 检查只有private构造函数的类是否声明为final -->
<module name="FinalClass"/>
<!-- 检查接口是否仅定义类型 -->
<module name="InterfaceIsType"/>
<!-- 检查类成员的可见度 检查类成员的可见性。只有static final 成员是public的
除非在本检查的protectedAllowed和packagedAllowed属性中进行了设置-->
<module name="VisibilityModifier">
<property name="packageAllowed" value="true"/>
<property name="protectedAllowed" value="true"/>
</module>
<!-- 语法 -->
<!-- String的比较不能用!= 和 == -->
<module name="StringLiteralEquality"/>
<!-- 限制for循环最多嵌套2层 -->
<module name="NestedForDepth">
<property name="max" value="2"/>
</module>
<!-- if最多嵌套3层 -->
<module name="NestedIfDepth">
<property name="max" value="3"/>
</module>
<!-- 检查未被注释的main方法,排除以Appllication结尾命名的类 -->
<module name="UncommentedMain">
<property name="excludedClasses" value=".*[Application,Test]$"/>
</module>
<!-- 禁止使用System.out.println -->
<module name="Regexp">
<property name="format" value="System\.out\.println"/>
<property name="illegalPattern" value="true"/>
</module>
<!-- return个数 3个-->
<module name="ReturnCount">
<property name="max" value="3"/>
</module>
<!--try catch 异常处理数量 3-->
<module name="NestedTryDepth ">
<property name="max" value="3"/>
</module>
<!-- clone方法必须调用了super.clone() -->
<module name="SuperClone" />
<!-- finalize 必须调用了super.finalize() -->
<module name="SuperFinalize" />
</module>
</module>
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<module name="Checker">
<!-- 检查文件是否以一个空行结束 -->
<module name="NewlineAtEndOfFile">
<property name="lineSeparator" value="lf" />
</module>
<!-- 文件长度不超过1500行 -->
<module name="FileLength">
<property name="max" value="1500"/>
</module>
<!-- 每个java文件一个语法树 -->
<module name="TreeWalker">
<!-- import检查-->
<!-- 避免使用* -->
<module name="AvoidStarImport">
<property name="excludes" value="java.io,java.net,java.lang.Math"/>
<!-- 实例;import java.util.*;.-->
<property name="allowClassImports" value="false"/>
<!-- 实例 ;import static org.junit.Assert.*;-->
<property name="allowStaticMemberImports" value="true"/>
</module>
<!-- 检查是否从非法的包中导入了类 -->
<module name="IllegalImport"/>
<!-- 检查是否导入了多余的包 -->
<module name="RedundantImport"/>
<!-- 没用的import检查,比如:1.没有被用到2.重复的3.import java.lang的4.import 与该类在同一个package的 -->
<module name="UnusedImports" />
<!-- 注释检查 -->
<!-- 检查方法和构造函数的javadoc -->
<module name="JavadocType">
<property name="allowUnknownTags" value="true"/>
<message key="javadoc.missing" value="类注释:缺少Javadoc注释。"/>
</module>
<module name="JavadocMethod">
<property name="tokens" value="METHOD_DEF" />
<!--允许get set 方法没有注释-->
<property name="allowMissingPropertyJavadoc" value="true"/>
<message key="javadoc.missing" value="方法注释:缺少Javadoc注释。"/>
</module>
<!-- 命名检查 -->
<!-- 局部的final变量,包括catch中的参数的检查 -->
<module name="LocalFinalVariableName" />
<!-- 局部的非final型的变量,包括catch中的参数的检查 -->
<module name="LocalVariableName" />
<!-- 包名的检查(只允许小写字母),默认^[a-z]+(\.[a-zA-Z_][a-zA-Z_0-9_]*)*$ -->
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$" />
<message key="name.invalidPattern" value="包名 ''{0}'' 要符合 ''{1}''格式."/>
</module>
<!-- 仅仅是static型的变量(不包括static final型)的检查 -->
<module name="StaticVariableName" />
<!-- Class或Interface名检查,默认^[A-Z][a-zA-Z0-9]*$-->
<module name="TypeName">
<property name="severity" value="warning"/>
<message key="name.invalidPattern" value="名称 ''{0}'' 要符合 ''{1}''格式."/>
</module>
<!-- 非static型变量的检查 -->
<module name="MemberName" />
<!-- 方法名的检查 -->
<module name="MethodName" />
<!-- 方法的参数名 -->
<module name="ParameterName " />
<!-- 常量名的检查(只允许大写),默认^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$ -->
<module name="ConstantName" />
<!-- 定义检查 -->
<!-- 检查数组类型定义的样式 -->
<module name="ArrayTypeStyle"/>
<!-- 检查long型定义是否有大写的“L” -->
<module name="UpperEll"/>
<!-- 长度检查 -->
<!-- 每行不超过120个字符 -->
<module name="LineLength">
<property name="max" value="120" />
</module>
<!-- 方法不超过50行 -->
<module name="MethodLength">
<property name="tokens" value="METHOD_DEF" />
<property name="max" value="75" />
</module>
<!-- 方法的参数个数不超过5个。 并且不对构造方法进行检查-->
<module name="ParameterNumber">
<property name="max" value="5" />
<property name="ignoreOverriddenMethods" value="true"/>
<property name="tokens" value="METHOD_DEF" />
</module>
<!-- 空格检查-->
<!-- 方法名后跟左圆括号"(" -->
<module name="MethodParamPad" />
<!-- 在类型转换时,不允许左圆括号右边有空格,也不允许与右圆括号左边有空格 -->
<module name="TypecastParenPad" />
<!-- 检查在某个特定关键字之后应保留空格 -->
<module name="NoWhitespaceAfter"/>
<!-- 检查在某个特定关键字之前应保留空格 -->
<module name="NoWhitespaceBefore"/>
<!-- 操作符换行策略检查 -->
<module name="OperatorWrap"/>
<!-- 圆括号空白 -->
<module name="ParenPad"/>
<!-- 检查分隔符是否在空白之后 -->
<module name="WhitespaceAfter"/>
<!-- 检查分隔符周围是否有空白 -->
<module name="WhitespaceAround"/>
<!-- 修饰符检查 -->
<!-- 检查修饰符的顺序是否遵照java语言规范,默认public、protected、private、abstract、static、final、transient、volatile、synchronized、native、strictfp -->
<module name="ModifierOrder"/>
<!-- 检查接口和annotation中是否有多余修饰符,如接口方法不必使用public -->
<module name="RedundantModifier"/>
<!-- 代码块检查 -->
<!-- 检查是否有嵌套代码块 -->
<module name="AvoidNestedBlocks"/>
<!-- 检查是否有空代码块 -->
<module name="EmptyBlock"/>
<!-- 检查左大括号位置 -->
<module name="LeftCurly"/>
<!-- 检查代码块是否缺失{} -->
<module name="NeedBraces"/>
<!-- 检查右大括号位置 -->
<module name="RightCurly"/>
<!-- 代码检查 -->
<!-- 检查空的代码段 -->
<module name="EmptyStatement"/>
<!-- 检查在重写了equals方法后是否重写了hashCode方法 -->
<module name="EqualsHashCode"/>
<!-- 检查局部变量或参数是否隐藏了类中的变量 -->
<module name="HiddenField">
<property name="tokens" value="VARIABLE_DEF"/>
</module>
<!-- 检查是否使用工厂方法实例化 -->
<module name="IllegalInstantiation"/>
<!-- 检查子表达式中是否有赋值操作 -->
<module name="InnerAssignment"/>
<!-- 检查是否有"魔术"数字 -->
<module name="MagicNumber">
<property name="ignoreNumbers" value="0, 1"/>
<property name="ignoreAnnotation" value="true"/>
</module>
<!-- 检查switch语句是否有default -->
<module name="MissingSwitchDefault"/>
<!-- 检查是否有过度复杂的布尔表达式 -->
<module name="SimplifyBooleanExpression"/>
<!-- 检查是否有过于复杂的布尔返回代码段 -->
<module name="SimplifyBooleanReturn"/>
<!-- 类设计检查 -->
<!-- 检查类是否为扩展设计l -->
<!-- 检查只有private构造函数的类是否声明为final -->
<module name="FinalClass"/>
<!-- 检查工具类是否有putblic的构造器 -->
<module name="HideUtilityClassConstructor"/>
<!-- 检查接口是否仅定义类型 -->
<module name="InterfaceIsType"/>
<!-- 检查类成员的可见度 检查类成员的可见性。只有static final 成员是public的
除非在本检查的protectedAllowed和packagedAllowed属性中进行了设置-->
<module name="VisibilityModifier">
<property name="packageAllowed" value="true"/>
<property name="protectedAllowed" value="true"/>
</module>
<!-- 语法 -->
<!-- String的比较不能用!= 和 == -->
<module name="StringLiteralEquality"/>
<!-- 限制for循环最多嵌套2层 -->
<module name="NestedForDepth">
<property name="max" value="2"/>
</module>
<!-- if最多嵌套3层 -->
<module name="NestedIfDepth">
<property name="max" value="3"/>
</module>
<!-- 检查未被注释的main方法,排除以Appllication结尾命名的类 -->
<module name="UncommentedMain">
<property name="excludedClasses" value=".*Application$"/>
</module>
<!-- 禁止使用System.out.println -->
<module name="Regexp">
<property name="format" value="System\.out\.println"/>
<property name="illegalPattern" value="true"/>
</module>
<!-- return个数 3个-->
<module name="ReturnCount">
<property name="max" value="3"/>
</module>
<!--try catch 异常处理数量 3-->
<module name="NestedTryDepth ">
<property name="max" value="3"/>
</module>
<!-- clone方法必须调用了super.clone() -->
<module name="SuperClone" />
<!-- finalize 必须调用了super.finalize() -->
<module name="SuperFinalize" />
</module>
</module>
# 开发工具和插件使用指南
版本:v1.0
时间:2019-02-09
[TOC]
## [强制] Intellij IDEA
集成开发环境(IDE)统一使用Intellij IDEA,版本2016及以上,建议安装Intellij IDEA 2018
下载地址:http://www.jetbrains.com/idea/download/#section=windows
注册码:http://idea.lanyus.com/ 建议使用补丁或搭建本地服务器 //有钱买正版
- 下载JetbrainsIdesCrack-4.2.jar
- 复制JetbrainsIdesCrack-4.2.jar至Intellij 安装目录下的lib目录
```
Intellij 安装目录/JetBrains/lib/JetbrainsIdesCrack-4.2.jar
```
- 在Intellij 安装目录下的bin目录找到idea64.exe.vmoptions(64位)或idea.exe.vmoptions(32位)编辑
```
//在最后一行增加-javaagent:../lib/JetbrainsIdesCrack-4.2.jar
//并且这句话的前后空行
-Xms128m
-Xmx750m
-XX:ReservedCodeCacheSize=240m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-Djdk.http.auth.tunneling.disabledSchemes=""
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
-javaagent:../lib/JetbrainsIdesCrack-3.4-release-enc.jar
```
- 重新打开Intellij,打开激活窗口,选择激活码方式,填入以下激活码(注: 内容可自行修改)
```
{"licenseId":"ThisCrackLicenseId",
"licenseeName":"随便填",
"assigneeName":"随便填",
"assigneeEmail":"邮箱,随便填",
"licenseRestriction":"描述信息,随便填",
"checkConcurrentUse":false,
"products":[
{"code":"II","paidUpTo":"2099-12-31"},
{"code":"DM","paidUpTo":"2099-12-31"},
{"code":"AC","paidUpTo":"2099-12-31"},
{"code":"RS0","paidUpTo":"2099-12-31"},
{"code":"WS","paidUpTo":"2099-12-31"},
{"code":"DPN","paidUpTo":"2099-12-31"},
{"code":"RC","paidUpTo":"2099-12-31"},
{"code":"PS","paidUpTo":"2099-12-31"},
{"code":"DC","paidUpTo":"2099-12-31"},
{"code":"RM","paidUpTo":"2099-12-31"},
{"code":"CL","paidUpTo":"2099-12-31"},
{"code":"PC","paidUpTo":"2099-12-31"},
{"code":"DB","paidUpTo":"2099-12-31"},
{"code":"GO","paidUpTo":"2099-12-31"},
{"code":"RD","paidUpTo":"2099-12-31"}
],
"hash":"2911276/0",
"gracePeriodDays":7,
"autoProlongated":false}
```
- 点击保存即可
## [强制] 阿里代码规约插件
阿里代码规约检查插件,是基于阿里Java开发规范的代码检查工具
1. 打开 File >> Settings >> Plugins 在搜索栏检索Alibaba, 点击安装
![1](https://i.loli.net/2019/02/11/5c618ef76260a.jpg)
2. 安装完成在Intellij 工具栏出现以下按钮
![2](https://i.loli.net/2019/02/11/5c618ec959ca3.jpg)
3. 或者选择 tools >> 阿里编程规约
![3](https://i.loli.net/2019/02/11/5c618f20f07ec.jpg)
4. 运行代码检查,根据提示修改代码
![4](https://i.loli.net/2019/02/11/5c618f42bc1bb.jpg)
## [强制] Check Style插件
Check Style代码格式检查
1. 打开 File >> Settings >> Plugins 在搜索栏检索CheckStyle, 点击安装
![22](https://i.loli.net/2019/02/11/5c619030550e8.jpg)
2. 配置ali check style文件 提供ali check style simple.xml 和 ali check style strict.xml,ali check style simple是必需的,有信息可以尝试ali check style strict
![22](https://i.loli.net/2019/02/11/5c61904d613dc.jpg)
3. 在待检查文件内使用右键或者在底部工具栏选择checkStyle-IDE运行格式检查,在运行前可以使用快捷键全文件格式化一次
![22](https://i.loli.net/2019/02/11/5c619070ec0bd.jpg)
![22](https://i.loli.net/2019/02/11/5c6190912798b.jpg)
4. File >> Setting >> Editor >> Code Style 载入ali check style simple.xml 或者 ali check style strict.xml 可实现代码按照标准格式化
![5](https://i.loli.net/2019/02/12/5c624193b9c5e.jpg)
## [强制] Find Bugs插件
Java静态分析工具Find Bugs插件可以帮助发现一些隐藏的bug。需要说明的是,Find Bugs插件发现的bug有时可能会产生误告警
1. 打开 File >> Settings >> Plugins 在搜索栏检索Find Bugs, 点击安装
![5](https://i.loli.net/2019/02/11/5c6190c236660.jpg)
2. 安装完成后在底部会出现FindBugs-IDE 工具tab
![6](https://i.loli.net/2019/02/11/5c6190d41d5de.jpg)
3. 选择文件或者目录,点击FindBugs-IDE或者右键选择FindBugs,执行检查
![7](https://i.loli.net/2019/02/11/5c6190e997e67.jpg)
![8](https://i.loli.net/2019/02/11/5c6190fd0cde9.jpg)
4. File >> setting >> Other Setting >> Findbugs 可以对规则进行选择和设置
![9](https://i.loli.net/2019/02/11/5c61911b68864.jpg)
## [强制] Find Security插件
Find Security 是Find Bugs的一个配置选项,默认为选择,请确保出选项被选择
![10](https://i.loli.net/2019/02/11/5c61912a500dc.jpg)
## [强制] JavaDoc插件
Intellij 自带JavaDoc工具,要生成JavaDoc文档需要完成以下两个配置
**JavaDoc模板**
常用的JavaDoc标签
<table>
<thead>
<tr>
<th>标签</th>
<th>描述</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>@author</td>
<td>标识一个类的作者</td>
<td>@author description</td>
</tr>
<tr>
<td>@version</td>
<td>指定类的版本</td>
<td>@version info</td>
</tr>
<tr>
<td>@date</td>
<td>创建时间</td>
<td>@date date time</td>
</tr>
<tr>
<td>@since</td>
<td>标记当引入一个特定的变化时</td>
<td>@since release</td>
</tr>
<tr>
<td>@deprecated</td>
<td>指名一个过期的类或成员</td>
<td>@deprecated description</td>
</tr>
<tr>
<td>@param</td>
<td>说明一个方法的参数</td>
<td>@param parameter-name explanation</td>
</tr>
<tr>
<td>@return</td>
<td>说明返回值类型</td>
<td>@return explanation</td>
</tr>
<tr>
<td>@throws</td>
<td>和 @exception标签一样.</td>
<td>The @throws tag has the same meaning as the @exception tag.</td>
</tr>
<tr>
<td>@see</td>
<td>指定一个到另一个主题的链接</td>
<td>@see class </td>
</tr>
</tbody></table>
1. File >> Setting >> Plugins 安装JavaDoc2
![15](https://i.loli.net/2019/02/11/5c61913c6b847.jpg)
2. File >> Setting >> Other Settings >> JavaDoc 设置class和interface的头说明
![16](https://i.loli.net/2019/02/11/5c61914b70646.jpg)
```
//Class
/**\n
* Describe class function detail.\n
* \n
* @author C.T \n
* @date <#if 1==1>${.now?string["yyyy-MM-dd HH:mm:ss"]}</#if> \n
* @version v1.0 \n
* @since jdk1.8 \n
<#if element.typeParameters?has_content> * \n
</#if>
<#list element.typeParameters as typeParameter>
* @param <${typeParameter.name}> the type parameter\n
</#list>
*/
//Interface
/**\n
* Describe interface function detail.\n
* \n
* @author C.T \n
* @date <#if 1==1>${.now?string["yyyy-MM-dd HH:mm:ss"]}</#if> \n
* @version v1.0 \n
* @since jdk1.8 \n
<#if element.typeParameters?has_content> * \n
</#if>
<#list element.typeParameters as typeParameter>
* @param <${typeParameter.name}> the type parameter\n
</#list>
*/
```
3. 通过JavaDoc的快捷键或者generator工具可以自动生成JavaDoc,生成时支持一次全部生成和选择指定对象生成
![17](https://i.loli.net/2019/02/11/5c61915e9b5d5.jpg)
![18](https://i.loli.net/2019/02/11/5c619172cf42c.jpg)
![17](https://i.loli.net/2019/02/11/5c619184cf681.jpg)
**运行时参数配置**
1. Tools >> Generate JavaDoc
![11](https://i.loli.net/2019/02/11/5c619195f0523.jpg)
2. 选择范围以及设置运行参数
![12](https://i.loli.net/2019/02/11/5c6191a91bc66.jpg)
```
//中文
Locale : zh_CN
//encoding UTF-8 -charset UTF-8 解决中文编码问题
//-windowtitle "接口文档" 设置文档title
//-link http://docs.Oracle.com/javase/8/docs/api //指定API版本是jdk8
Other command line arguments: encoding utf-8 -charset utf-8 -tag date:a:”date” -link http://docs.Oracle.com/javase/8/docs/api
```
3. 点击 OK 运行
![13](https://i.loli.net/2019/02/11/5c6191b8ca0a1.jpg)
## [强制] Apiggs插件
Apiggs是一款基于JavaDoc的restful接口文档生成工具
install
```
<!--自动生成restful接口文档-->
<plugin>
<groupId>com.github.fengyuchenglun</groupId>
<artifactId>apiggs-maven-plugin</artifactId>
<version>1.0.10</version>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>apiggs</goal>
</goals>
</execution>
</executions>
<configuration>
<showValidField>false</showValidField>
<controller>CosmoController</controller>
<responseBody>CosmoController</responseBody>
</configuration>
</plugin>
```
可选Option
```
id 项目id,生成id.html文件
title 文档标题
description 文档描述
production 输出文件夹,默认为 apiggs
out 输出目录,默认为 target
source 源码目录
dependency 源码依赖的代码目录,以逗号隔开
jar 源码依赖的jar包目录,以逗号隔开
ignore 忽略某些类型
version 文档版本号
```
可参考后台框架DEMO工程中的例子
## [推荐] TestNG插件
TestNg单元测试框架,安装TestNg插件,可以快速,自动创建TestNg单元测试类
1. File >> Settings >> Plugins 在搜索栏检索TestNG, 点击安装
![;20](https://i.loli.net/2019/02/11/5c6191cab72fb.jpg)
注意:这个插件目前支持TestNG5.6 如果Maven中使用版本与此有差异,手动调整自动生成的代码
2. 在需要写单元测试的类,右键选择generator >> test 完成相关配置即可自动生成,以Test结尾的java单元测试类
![21](https://i.loli.net/2019/02/11/5c6191daeb989.jpg)
## [强制] Git插件
Git作为分布式版本管理系统
1. 下载并安装Git,参考https://git-scm.com/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%AE%89%E8%A3%85-Git
2. 在intellij设置Git信息
![26](https://i.loli.net/2019/02/11/5c6191f2ecb24.jpg)
3. 选择文件,右键使用Git UI操作完成Git操作
![27](https://i.loli.net/2019/02/11/5c619201c56c1.jpg)
4. 安装Commit Message Template确保提交使用统一模板
![34](https://i.loli.net/2019/02/12/5c6234f2e7032.jpg)
5. 设置模板
copy
```
<type>(<scope>): <subject>
<body>
<footer>
```
![34](https://i.loli.net/2019/02/12/5c624008c3dc1.jpg)
6. 提交时 请确保这些选项被选中
![31](https://i.loli.net/2019/02/12/5c62324f1fd17.jpg)
7. 点击 Commit Message 右边编辑按钮,载入模板,按照Commit message 的格式修改内容
![31](https://i.loli.net/2019/02/12/5c6240d7af7ad.jpg)
Commit message 的格式
Commit message 都包括三个部分:Header,Body 和 Footer
```
//Header 是必需的,Body 和 Footer 可以省略
<type>(<scope>): <subject>
// 空一行
<body>
// 空一行
<footer>
```
- Header部分只有一行,包括三个字段:`type`(必需)、`scope`(可选)和`subject`(必需)
type用于说明 commit 的类别,只允许使用下面7个标识,如果type为feat和fix,则该 commit 将肯定出现在 Change log 之中。其他情况(docs、chore、style、refactor、test)建议不要放入 Change log
```
feat:新功能(feature)
fix:修补bug
docs:文档(documentation)
style: 格式(不影响代码运行的变动)
refactor:重构(即不是新增功能,也不是修改bug的代码变动)
test:增加测试
chore:构建过程或辅助工具的变动
```
scope用于说明 commit 影响的范围,不同功能模块
subject是 commit 目的的简短描述,不超过50个字符。
```
以动词开头,使用第一人称现在时,比如change,而不是changed或changes
第一个字母小写
结尾不加句号(.)
```
- Body 部分是对本次 commit 的详细描述,可以分成多行
```
//body 一般说明几个问题
做了什么事情
为什么做这个事情
怎么解决的问题
有什么影响
```
- Footer 部分只用于两种情况
```
//情况1
//当前代码与上一个版本不兼容,则 Footer 部分以BREAKING CHANGE开头,后面是对变动的描述、以及变动理由和迁移方法。
//例如
BREAKING CHANGE: isolate scope bindings definition has changed.
To migrate the code follow the example below:
Before:
scope: {
myAttr: 'attribute',
}
After:
scope: {
myAttr: '@',
}
The removed `inject` wasn't generaly useful for directives so there should be no code using it.
```
```
//情况2 关闭相关联的Issue,例如
Closes #234
//或者一次多个
Closes #123, #245, #992
```
\ No newline at end of file
# 代码规范
## 目录结构
<pre>
.
├── mock // mock文件
├── public // 公共文件 可以放一些第三方字体 样式库等
├── src
│ ├── components // 公共组件目录
│ ├── config.js // 项目配置文件
│ ├── global.less // 样式配置文件
│ ├── layouts // 布局目录
│ ├── models // 公共model存放位置
│ │ └── public.json // 公共model(public)文件,用于存放公共数据,比如:username
│ ├── services // 公共api存放位置
├── pages
│ │ ├── 404.js // 404页面
│ │ ├── home
│ │ │ ├── components // 首页公共组件
│ │ │ ├── index.js // 首页入口文件
│ │ │ ├── index.less // 首页样式
│ │ │ ├── models
│ │ │ │ └── home.js // 首页model文件(可以有多个,自动加载)
│ │ │ └── services
│ │ │  └── homeApi.js // 首页api文件
│ │ ├── document.ejs // 项目模板文件
│ │ ├── exception // 异常路由
│ │ │ ├── 404
│ │ │ │ └── index.js
│ │ └── index.js // 跟目录路由文件
│ ├── themes
│ │ └── vars.less // 项目主体配置文件
│ └── utils
│  └── index.js // 项目工具文件
└── package.json // 项目依赖配置文件
</pre>
## 约定
1. 所有的文件夹全部小写, 组件大驼峰,其他小驼峰。
2. 组件必须用`index.js`文件  导出具体组件文件
3. 所有文件以`.js` 后缀结尾,不要使用`.jsx`
4. 缩紧统一使用 2 个空格
5. 修改顶部有著名(有写作者是谁)的文件,必须通知到作者本人,授权后方可修改
6. 项目下 `master``dev`分支为保护分支,开发人员应该基于 dev 分支创建自己的开发分支
7. 每天下班前提交代码, 正常情况下都要在提交代码后请求合并到 dev 分支,并写好合并代码注解,然后每天上班第一件事拉取`dev`分支最新代码到自己的开发分支
8.  待添加
# 前端UI开发通用规范
版本:v1.0
时间:2019-01-28
由于前端UI框架采用阿里蚂蚁金服的antDesign,因此直接使用antDesign的设计语言作为前端UI开发的通用规范,此规范主要用于指导UI设计师和产品PD的设计工作,同时部分内容对开发人员有指导意义
具体内容,点击以下链接
**Web 设计指引** http://design.alipay.com/design/web/principle
具体项目,可以根据实际情况对以上设计通用规范进行调整,调整内容请用文档记录,并保存在产品或项目的文档目录留存
# 工具
规范一下开发工具
## VSCode
我们建议大家使用`VSCode`来作为我们的  代码开发工具,这里是[下载地址](https://code.visualstudio.com/)
### 插件
安装好 IDE 后请安装`Prettier`(我们默认通过此插件来格式化代码)
安装好`Prettier`后,请在 `vscode`的设置中添加如下设置
```json
"editor.tabSize": 2,
"eslint.autoFixOnSave": true,
```
这样可以在保持代码的时候自动格式化
## Git
我们统一使用`git`来进行代码管理,所以大家要掌握`git`的基础使用方式。正常情况下,使用`git`有两种方式,一是界面操作,代表工具是[SourceTree](https://www.sourcetreeapp.com/),二是命令行[操作](http://www.ruanyifeng.com/blog/2018/10/git-internals.html)。熟悉自己的就是最好的,不具体对比优劣。
## 代码检查
我们在脚手架里内置了代码检查,是基于`ESLint`,规则是在`airbnb`上做了一些定制化修改,简单来说就是代码提交的时候不允许有"红线"(IDE 的异常提醒),因为只有解决了这些警告,才允许提交代码,这个是强制的。
# 数据库脚本管理Flyway
## 什么是Flyway
Flyway是一款开源的数据库版本管理工具,它更倾向于规约优于配置的方式。Flyway可以独立于应用实现管理并跟踪数据库变更,支持数据库版本自动升级,并且有一套默认的规约,不需要复杂的配置,Migrations可以写成SQL脚本,也可以写在Java代码中,不仅支持Command Line和Java API,还支持Build构建工具和Spring Boot等,同时在分布式环境下能够安全可靠地升级数据库,同时也支持失败恢复等。
Flyway主要基于6种基本命令:`Migrate`, `Clean`, `Info`, `Validate`, `Baseline` and `Repair`,稍候会逐一分析讲解。目前支持的数据库主要有:Oracle, SQL Server, SQL Azure, DB2, DB2 z/OS, MySQL(including Amazon RDS), MariaDB, Google Cloud SQL, PostgreSQL(including Amazon RDS and Heroku), Redshift, Vertica, H2, Hsql, Derby, SQLite, SAP HANA, solidDB, Sybase ASE and Phoenix.
*PS:不⽀持分布式数据库,譬如阿⾥云的DRDS*
## Flyway如何工作的?
Flyway对数据库进行版本管理主要由Metadata表和6种命令完成,Metadata主要用于记录元数据,每种命令功能和解决的问题范围不一样,以下分别对metadata表和这些命令进行阐述,其中的示意图都来自Flyway的官方文档。
#### Metadata Table
Flyway中最核心的就是用于记录所有版本演化和状态的Metadata表,在Flyway首次启动时会创建默认名为`SCHEMA_VERSION`的元数据表,其表结构为(以MySQL为例):
| Field | Type | Null | Key | Default |
| :------------: | :-----------: | :--: | :--: | :---------------: |
| version_rank | int(11) | NO | MUL | NULL |
| installed_rank | int(11) | NO | MUL | NULL |
| version | varchar(50) | NO | PRI | NULL |
| description | varchar(200) | NO | | NULL |
| type | varchar(20) | NO | | NULL |
| script | varchar(1000) | NO | | NULL |
| checksum | int(11) | YES | | NULL |
| installed_by | varchar(100) | NO | | NULL |
| installed_on | timestamp | NO | | CURRENT_TIMESTAMP |
| execution_time | int(11) | NO | | NULL |
| success | tinyint(1) | NO | MUL | NULL |
#### Migrate
Migrate是指把数据库Schema迁移到最新版本,是Flyway工作流的核心功能,Flyway在Migrate时会检查Metadata(元数据)表,如果不存在会创建Metadata表,Metadata表主要用于记录版本变更历史以及Checksum之类的。
![img](https://blog.waterstrong.me/assets/flyway-in-practice/command_migrate.png)
Migrate时会扫描指定文件系统或Classpath下的Migrations(可以理解为数据库的版本脚本),并且会逐一比对Metadata表中的已存在的版本记录,如果有未应用的Migrations,Flyway会获取这些Migrations并按次序Apply到数据库中,否则不需要做任何事情。另外,通常在应用程序启动时应默认执行Migrate操作,从而避免程序和数据库的不一致性。
#### Clean
Clean相对比较容易理解,即清除掉对应数据库Schema中的所有对象,包括表结构,视图,存储过程,函数以及所有的数据等都会被清除。
[![img](https://blog.waterstrong.me/assets/flyway-in-practice/command_clean.png)](https://blog.waterstrong.me/assets/flyway-in-practice/command_clean.png)
Clean操作在开发和测试阶段是非常有用的,它能够帮助快速有效地更新和重新生成数据库表结构,但特别注意的是:不应在Production的数据库上使用!
#### Info
Info用于打印所有Migrations的详细和状态信息,其实也是通过Metadata表和Migrations完成的,下图很好地示意了Info打印出来的信息。
[![img](https://blog.waterstrong.me/assets/flyway-in-practice/command_info.png)](https://blog.waterstrong.me/assets/flyway-in-practice/command_info.png)
Info能够帮助快速定位当前的数据库版本,以及查看执行成功和失败的Migrations。
#### Validate
Validate是指验证已经Apply的Migrations是否有变更,Flyway是默认是开启验证的。
[![img](https://blog.waterstrong.me/assets/flyway-in-practice/command_validate.png)](https://blog.waterstrong.me/assets/flyway-in-practice/command_validate.png)
Validate原理是对比Metadata表与本地Migrations的Checksum值,如果值相同则验证通过,否则验证失败,从而可以防止对已经Apply到数据库的本地Migrations的无意修改。
#### Baseline
Baseline针对已经存在Schema结构的数据库的一种解决方案,即实现在非空数据库中新建Metadata表,并把Migrations应用到该数据库。
[![img](https://blog.waterstrong.me/assets/flyway-in-practice/command_baseline.png)](https://blog.waterstrong.me/assets/flyway-in-practice/command_baseline.png)
Baseline可以应用到特定的版本,这样在已有表结构的数据库中也可以实现添加Metadata表,从而利用Flyway进行新Migrations的管理了。
#### Repair
Repair操作能够修复Metadata表,该操作在Metadata表出现错误时是非常有用的。
[![img](https://blog.waterstrong.me/assets/flyway-in-practice/command_repair.png)](https://blog.waterstrong.me/assets/flyway-in-practice/command_repair.png)
Repair会修复Metadata表的错误,通常有两种用途:
- 移除失败的Migration记录,该问题只是针对不支持DDL事务的数据库。
- 重新调整已经应用的Migratons的Checksums值,比如:某个Migratinon已经被应用,但本地进行了修改,又期望重新应用并调整Checksum值,不过尽量不要这样操作,否则可能造成其它环境失败。
## 如何使用Flyway?
这里将主要关注在Gradle和Spring Boot中集成并使用Flyway,数据库通常会采用MySQL、PostgreSQL、H2或Hsql等。
#### 正确创建Migrations
**Migrations**是指Flyway在更新数据库时是使用的版本脚本,比如:一个基于Sql的Migration命名为`V1__init_tables.sql`,内容即是创建所有表的sql语句,另外,Flyway也支持基于Java的Migration。Flyway加载Migrations的默认Locations为`classpath:db/migration`,也可以指定`filesystem:/project/folder`,其加载是在Runtime自动递归地执行的。
[![img](https://blog.waterstrong.me/assets/flyway-in-practice/sql_migration_base_dir.png)](https://blog.waterstrong.me/assets/flyway-in-practice/sql_migration_base_dir.png)
除了需要指定Location外,Flyway对Migrations的扫描还必须遵从一定的命名模式,Migration主要分为两类:Versioned和Repeatable。
- **Versioned migrations**
一般常用的是Versioned类型,用于版本升级,每一个版本都有一个唯一的标识并且只能被应用一次,并且不能再修改已经加载过的Migrations,因为Metadata表会记录其Checksum值。其中的version标识版本号,由一个或多个数字构成,数字之间的分隔符可以采用点或下划线,在运行时下划线其实也是被替换成点了,每一部分的前导零会被自动忽略。
- **Repeatable migrations**
Repeatable是指可重复加载的Migrations,其每一次的更新会影响Checksum值,然后都会被重新加载,并不用于版本升级。对于管理不稳定的数据库对象的更新时非常有用。Repeatable的Migrations总是在Versioned之后按顺序执行,但开发者必须自己维护脚本并且确保可以重复执行,通常会在sql语句中使用`CREATE OR REPLACE`来保证可重复执行。
默认情况下基于Sql的Migration文件的命令规则如下图所示:
[![img](https://blog.waterstrong.me/assets/flyway-in-practice/sql_migration_naming.png)](https://blog.waterstrong.me/assets/flyway-in-practice/sql_migration_naming.png)
其中的文件名由以下部分组成,除了使用默认配置外,某些部分还可自定义规则。
- prefix: 可配置,前缀标识,默认值`V`表示Versioned,`R`表示Repeatable
- version: 标识版本号,由一个或多个数字构成,数字之间的分隔符可用点`.`或下划线`_`
- separator: 可配置,用于分隔版本标识与描述信息,默认为两个下划线`__`
- description: 描述信息,文字之间可以用下划线或空格分隔
- suffix: 可配置,后续标识,默认为`.sql`
## flyway 最佳实践
1. SQL 的文件名
开发环境和生产环境的 migration SQL 不共用. 开发过程往往是多人协作开发, DB migration 也相对比较频繁, 所以 SQL 脚本会很多. 而生产环境 DB migration 往往由 DBA 完成, 每次升级通常需要提交一个 SQL 脚本.
(1). 开发环境 SQL 文件建议采用时间戳作为版本号.
开发环境 SQL 文件建议采用时间戳作为版本号, 多人一起开发不会导致版本号争用, 同时再加上生产环境的版本号, 这样的话, 将来手工 merge 成生产环境 V1.2d migration 脚本也比较方便, SQL 文件示例:
V20180317.10.59__V1.2_Unique_User_Names.sql
V20180317.14.59__V1.2_Add_SomeTables.sql
(2). 生产环境 SQL 文件, 应该是手动 merge 开发环境的 SQL 脚本, 版本号按照正常的版本, 比如
V2.1.5_001__Unique_User_Names.sql
2. migration 后的SQL 脚本不应该再被修改.
3. R版本的脚本编写,需要编写者注意控制脚本操作的幂等性.
4. SQL文件命名参考:
V20190110.10.23__V1.0_Create_Table.sql
V20190110.10.55__V1.0_Init_Data.sql
R20190115.20.00__V1.0_Update_Modulexxx.sql (按模块修改)
R20190117.21.00__V1.0_Update_Modulexxx.sql (按模块修改)
V20190201.17.59__V1.1_Create_Table.sql (新版本)
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment