Commit 225ca035 authored by 康明's avatar 康明

Init

parents
File added
# 代码管理规范
开发新功能时,评估当前功能如果后期不使用会不会影响系统使用,如果关联性较强建议新建一个分支开发新功能
- 尽量划分小功能模块提交,便于找出问题模块的代码
- 迭代版本后,拉取最新的master代码进行下一阶段的dev开发
- 规范填写commit message,至少填写开发了什么模块,修复了什么bug
- 如有新的模块,记得补充README
## 撰写提交信息
提交commit时,必须给出完整扼要的提交信息,规范格式如下:
:::info
[Type]: subject
Type包括:
feat:新功能(feature)
fix:修补bug
docs:文档(documentation)
style: 格式(不影响代码运行的变动)
refactor:重构(即不是新增功能,也不是修改bug的代码变动)
test:增加测试
build: 对项目构建或者依赖的改动
revert: feat(pencil): add 'graphiteWidth' option (撤销之前的commit)
:::
例:
:::info
[fix]: 修复新增楼栋无法关联项目
:::
# Java开发注意事项
# 一、异常
## 1. 六类典型空指针问题
- 包装类型的空指针问题
```java
public class NullPointTest {
public static void main(String[] args) throws InterruptedException {
System.out.println(testInteger(null));
}
private static Integer testInteger(Integer i) {
return i + 1; //包装类型,传参可能为null,直接计算,则会导致空指针问题
}
}
```
- 级联调用的空指针问题
```java
public class NullPointTest {
public static void main(String[] args) {
//fruitService.getAppleService() 可能为空,会导致空指针问题
fruitService.getAppleService().getWeight().equals("18");
}
}
```
- Equals方法左边的空指针问题
```java
public class NullPointTest {
public static void main(String[] args) {
String s = null;
if (s.equals("666")) { //s可能为空,会导致空指针问题
System.out.println("公众号:捡田螺的小男孩,666");
}
}
}
```
- ConcurrentHashMap 类似容器不支持 k-v为 null
```java
public class NullPointTest {
public static void main(String[] args) {
Map map = new ConcurrentHashMap<>();
String key = null;
String value = null;
map.put(key, value);
}
}
```
- 集合,数组直接获取元素
```java
public class NullPointTest {
public static void main(String[] args) {
int [] array=null;
List list = null;
System.out.println(array[0]); //空指针异常
System.out.println(list.get(0)); //空指针一场
}
}
```
- 对象直接获取属性
```java
public class NullPointTest {
public static void main(String[] args) {
User user=null;
System.out.println(user.getAge()); //空指针异常
}
}
```
## 2. 异常的几个坑
- **finally重新抛出的异常也要注意**
```java
public void wrong() {
try {
log.info("try");
//异常丢失
throw new RuntimeException("try");
} finally {
log.info("finally");
throw new RuntimeException("finally");
}
}
```
一个方法是不会出现两个异常的呢,所以finally的异常会把try的**异常覆盖**。正确的使用方式应该是,finally 代码块**负责自己的异常捕获和处理**
```java
public void right() {
try {
log.info("try");
throw new RuntimeException("try");
} finally {
log.info("finally");
try {
throw new RuntimeException("finally");
} catch (Exception ex) {
log.error("finally", ex);
}
}
}
```
# 二、Spring事务未生效
日常业务开发中,我们经常跟事务打交道,**事务失效**主要有以下几个场景:
- 底层数据库引擎不支持事务
- 在非public修饰的方法使用
- rollbackFor属性设置错误
- 本类方法直接调用
- 异常被try...catch吃了,导致事务失效。
其中,最容易踩的坑就是后面两个,**注解的事务方法给本类方法直接调用**,伪代码如下:
```java
public class TransactionTest{
public void A(){
//插入一条数据
//调用方法B (本地的类调用,事务失效了)
B();
}
@Transactional
public void B(){
//插入数据
}
}
```
如果用异常catch住,**那事务也是会失效呢**~,伪代码如下:
```java
@Transactional
public void method(){
try{
//插入一条数据
insertA();
//更改一条数据
updateB();
}catch(Exception e){
logger.error("异常被捕获了,那你的事务就失效咯",e);
}
}
```
# 三、数据访问
## 1. Mysql8数据库的时区坑
对mysql数据库进行升级,新版本为8.0.12。但是升级完之后,发现now()函数,获取到的时间比北京时间晚8小时,原来是因为mysql8默认为美国那边的时间,需要指定时区。
:::info
jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8& **serverTimezone=Asia/Shanghai**
:::
## 2. 数据库使用utf-8存储, 插入表情异常的坑
低版本的MySQL支持的utf8编码,最大字符长度为 3字节,但是呢,存储表情需要4个字节,因此如果用utf8存储表情的话,会报SQLException: Incorrect string value: '\xF0\x9F\x98\x84' for column,所以一般用utf8mb4编码去存储表情。
# 四、待定
## 1. 疏忽switch的return和break
```java
public class SwitchTest {
public static void main(String[] args) throws InterruptedException {
System.out.println("testSwitch结果是:"+testSwitch("1"));
}
private static String testSwitch(String key) {
switch (key) {
case "1":
System.out.println("1");
case "2":
System.out.println(2);
return "2";
case "3":
System.out.println("3");
default:
System.out.println("返回默认值");
return "4";
}
}
}
```
输出结果:
```java
1
2
testSwitch结果是:2
```
switch 是会**沿着case一直往下匹配的,直到遇到return或者break。** 所以,在写代码的时候留意一下,是不是你要的结果。
# WEB前端开发规范手册
| 文件状态: | 文件标识: | SINRA-TC-IG |
| --- | --- | --- |
| [] 草稿 | **当前版本:** | **1.1** |
| [    ] 正式发布 | **作者:** | **技术中心** |
| [    ] 正在修改 | **完成时间:** | **2020-08-10** |
版本历史
| 版本/状态 | 作者 | 参与者 | 起止日期 | 备注 |
| --- | --- | --- | --- | --- |
| 1.0 | 技术中心 | | 2020.08.03 | 模版定义 |
| 1.1 | 技术中心 | | 2020.08.10 | 初版形成 |
| | | | | |
# 前端开发规范
Front Standard Guide
# 前端 JS 项目开发规范
规范的目的是为了编写高质量的代码,让你的团队成员每天得心情都是愉悦的,大家在一起是快乐的。
引自《阿里规约》的开头片段:
_----现代软件架构的复杂性需要协同开发完成,如何高效地协同呢?无规矩不成方圆,无规范难以协同,比如,制订交通法规表面上是要限制行车权,实际上是保障公众的人身安全,试想如果没有限速,没有红绿灯,谁还敢上路行驶。对软件来说,适当的规范和标准绝不是消灭代码内容的创造性、优雅性,而是限制过度个性化,以一种普遍认可的统一方式一起做事,提升协作效率,降低沟通成本。代码的字里行间流淌的是软件系统的血液,质量的提升是尽可能少踩坑,杜绝踩重复的坑,切实提升系统稳定性,码出质量。_
# 一、编程规约
### (一)命名规范
#### 1.1.1 项目命名
全部采用小写方式, 以中划线分隔。
正例:`mall-management-system`
反例:`mall_management-system / mallManagementSystem`
#### 1.1.2 目录命名
以中划线分隔,有复数结构时,要采用复数命名法, 缩写不用复数
正例: `scripts / styles / components / images / utils / layouts / demo-styles / demo-scripts / img / doc`
反例: `script / style / demo_scripts / demoStyles / imgs / docs`
【特殊】VUE 的项目中的 components 中的组件目录,使用 kebab-case 或 PascalCase 命名
正例: `head-search / page-loading / authorized / notice-icon/ HeadSearch / PageLoading`
反例: `Head-search / Headsearch`
【特殊】VUE 的项目中的除 components 组件目录外的所有目录也使用 kebab-case 或 PascalCase 命名
正例: `page-one / shopping-car / user-management / ShoppingCar / UserManagement`
反例: `User-Management / userManagement`
#### 1.1.3 JS、CSS、SCSS、HTML、PNG 文件命名
全部采 kebab-case 或 PascalCase 命名用方式
正例: `render-dom.js / signup.css / index.html / company-logo.png / UserManagement.html`
反例: `renderDom.js / renderdo.js`
#### 1.1.4 命名严谨性
代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。 说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,即使纯拼音命名方式也要避免采用
正例:`henan / luoyang / rmb 等国际通用的名称,可视同英文。`
反例:`DaZhePromotion [打折] / getPingfenByName() [评分] / int 某变量 = 3`
**杜绝完全不规范的缩写,避免望文不知义:**
反例:AbstractClass“缩写”命名成 AbsClass;condition“缩写”命名成 condi,此类随意缩写严重降低了代码的可阅读性。
### (二)HTML 规范 (Vue Template 同样适用)
#### 1.2.1 HTML 类型
推荐使用 HTML5 的文档类型申明: .
(建议使用 text/html 格式的 HTML。避免使用 XHTML。XHTML 以及它的属性,比如 application/xhtml+xml 在浏览器中的应用支持与优化空间都十分有限)。
- 规定字符编码
- IE 兼容模式
- 规定字符编码
- doctype 大写
正例:
```
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta charset="UTF-8" />
<title>Page title</title>
</head>
<body>
<img src="images/company-logo.png" alt="Company" />
</body>
</html>
```
#### 1.2.2 缩进
缩进使用 2 个空格(一个 tab)
嵌套的节点应该缩进。
#### 1.2.3 分块注释
在每一个块状元素,列表元素和表格元素后,加上一对 HTML 注释。注释格式
```
### 1.2.4 语义化标签
HTML5 中新增很多语义化标签,所以优先使用语义化标签,避免一个页面都是 div 或者 p 标签
正例
```
<header></header>
<footer></footer>
```
反例
```
<div>
<p></p>
</div>
```
#### 1.2.5 引号
使用双引号(" ") 而不是单引号(’ ') 。
正例: ``
反例: ``
### (三) CSS 规范
#### 1.3.1 命名
- 类名使用小写字母,以中划线分隔
- id 采用驼峰式命名
- scss 中的变量、函数、混合、placeholder 采用驼峰式命名
ID 和 class 的名称总是使用可以反应元素目的和用途的名称,或其他通用的名称,代替表象和晦涩难懂的名称
不推荐:
```
.fw-800 {
font-weight: 800;
}
.red {
color: red;
}
```
推荐:
```
.heavy {
font-weight: 800;
}
.important {
color: red;
}
```
#### 1.3.2 选择器
1)css 选择器中避免使用标签名
从结构、表现、行为分离的原则来看,应该尽量避免 css 中出现 HTML 标签,并且在 css 选择器中出现标签名会存在潜在的问题。
2)很多前端开发人员写选择器链的时候不使用 直接子选择器(注:直接子选择器和后代选择器的区别)。有时,这可能会导致疼痛的设计问题并且有时候可能会很耗性能。然而,在任何情况下,这是一个非常不好的做法。如果你不写很通用的,需要匹配到 DOM 末端的选择器, 你应该总是考虑直接子选择器。
不推荐:
```
.content .title {
font-size: 2rem;
}
```
推荐:
```
.content > .title {
font-size: 2rem;
}
```
#### 1.3.3 尽量使用缩写属性
不推荐:
```
border-top-style: none;
font-family: palatino, georgia, serif;
font-size: 100%;
line-height: 1.6;
padding-bottom: 2em;
padding-left: 1em;
padding-right: 1em;
padding-top: 0;
```
推荐:
```
border-top: 0;
font: 100%/1.6 palatino, georgia, serif;
padding: 0 1em 2em;
```
#### 1.3.4 每个选择器及属性独占一行
不推荐:
```
button{
width:100px;height:50px;color:#fff;background:#00a0e9;
}
```
推荐:
```
button{
width:100px;
height:50px;
color:#fff;
background:#00a0e9;
}
```
#### 1.3.5 省略0后面的单位
不推荐:
```
div{
padding-bottom: 0px;
margin: 0em;
}
```
推荐:
```
div{
padding-bottom: 0;
margin: 0;
}
```
#### 1.3.6 避免使用ID选择器及全局标签选择器防止污染全局样式
不推荐:
```
#header{
padding-bottom: 0px;
margin: 0em;
}
```
推荐:
```
.header{
padding-bottom: 0px;
margin: 0em;
}
```
### (四) LESS 规范
#### 1.4.1 代码组织
##### 1)将公共scss文件放置在style/scss/common文件夹
例:// color.scss,common.scss
##### 2)按以下顺序组织
1、@import;
2、变量声明;
3、样式声明;
```
@import "mixins/size.less";
@default-text-color: #333;
.page {
width: 960px;
margin: 0 auto;
}
```
#### 1.4.2 避免嵌套层级过多
将嵌套深度限制在3级。对于超过4级的嵌套,给予重新评估。这可以避免出现过于详实的CSS选择器。
避免大量的嵌套规则。当可读性受到影响时,将之打断。推荐避免出现多于20行的嵌套规则出现
不推荐:
```
.main{
.title{
.name{
color:#fff
}
}
}
```
推荐:
```
.main-title{
.name{
color:#fff
}
}
```
### (五) Javascript 规范
#### 1.5.1 命名
##### 1) 采用小写驼峰命名 lowerCamelCase,代码中的命名均不能以下划线,也不能以下划线或美元符号结束
反例: `_name / name_ / name$`
##### 2) 方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从驼峰形式。
正例: `localValue / getHttpMessage() / inputUserId`
其中 method 方法命名必须是 动词 或者 动词+名词 形式****
正例:`saveShopCarData /openShopCarInfoDialog`
反例:`save / open / show / go`
特此说明,增删查改,详情统一使用如下 5 个单词,不得使用其他(目的是为了统一各个端)****
```
add / update / delete / detail / get
```
**附: 函数方法常用的动词:**
```
get 获取/set 设置,
add 增加/remove 删除
create 创建/destory 移除
start 启动/stop 停止
open 打开/close 关闭,
read 读取/write 写入
load 载入/save 保存,
create 创建/destroy 销毁
begin 开始/end 结束,
backup 备份/restore 恢复
import 导入/export 导出,
split 分割/merge 合并
inject 注入/extract 提取,
attach 附着/detach 脱离
bind 绑定/separate 分离,
view 查看/browse 浏览
edit 编辑/modify 修改,
select 选取/mark 标记
copy 复制/paste 粘贴,
undo 撤销/redo 重做
insert 插入/delete 移除,
add 加入/append 添加
clean 清理/clear 清除,
index 索引/sort 排序
find 查找/search 搜索,
increase 增加/decrease 减少
play 播放/pause 暂停,
launch 启动/run 运行
compile 编译/execute 执行,
debug 调试/trace 跟踪
observe 观察/listen 监听,
build 构建/publish 发布
input 输入/output 输出,
encode 编码/decode 解码
encrypt 加密/decrypt 解密,
compress 压缩/decompress 解压缩
pack 打包/unpack 解包,
parse 解析/emit 生成
connect 连接/disconnect 断开,
send 发送/receive 接收
download 下载/upload 上传,
refresh 刷新/synchronize 同步
update 更新/revert 复原,
lock 锁定/unlock 解锁
check out 签出/check in 签入,
submit 提交/commit 交付
push 推/pull 拉,
expand 展开/collapse 折叠
begin 起始/end 结束,
start 开始/finish 完成
enter 进入/exit 退出,
abort 放弃/quit 离开
obsolete 废弃/depreciate 废旧,
collect 收集/aggregate 聚集
```
##### 3) 常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。
正例: `MAX_STOCK_COUNT`
反例: `MAX_COUNT`
#### 1.5.2 代码格式
##### 1) 使用 2 个空格进行缩进
正例:
```
if (x < y) {
x += 10;
} else {
x += 1;
}
```
##### 2) 不同逻辑、不同语义、不同业务的代码之间插入一个空行分隔开来以提升可读性。
> 说明:任何情形,没有必要插入多个空行进行隔开。
#### 1.5.3 字符串
统一使用单引号(‘),不使用双引号(“)。这在创建 HTML 字符串非常有好处:
正例:
```
let str = 'foo';
let testDiv = '<div id="test"></div>';
```
反例:
```
let str = 'foo';
let testDiv = "<div id='test'></div>";
```
#### 1.5.4 对象声明
##### 1)使用字面值创建对象
正例: `let user = {};`
反例: `let user = new Object();`
##### 2) 使用字面量来代替对象构造器
正例:
```
var user = {
age: 0,
name: 1,
city: 3
};
```
反例:
```
var user = new Object();
user.age = 0;
user.name = 0;
user.city = 0;
```
#### 1.5.5 使用 ES6,7
优先使用 ES6,7 中新增的语法糖和函数。这将简化你的程序,并让你的代码更加灵活和可复用。
> 必须强制使用 ES6, ES7 的新语法,比如箭头函数、await/async , 解构, let , for…of 等等
#### 1.5.6 括号
下列关键字后必须有大括号(即使代码块的内容只有一行):if, else, for, while, do, switch, try, catch, finally, with。
正例:
```
if (condition) {
doSomething();
}
```
反例:
```
if (condition) doSomething();
```
#### 1.5.7 undefined 判断
永远不要直接使用 undefined 进行变量判断;使用 typeof 和字符串’undefined’对变量进行判断。
正例:
```
if (typeof person === 'undefined') {
...
}
```
反例:
```
if (person === undefined) {
...
}
```
#### 1.5.8 条件判断和循环最多三层
条件判断能使用三目运算符和逻辑运算符解决的,就不要使用条件判断,但是谨记不要写太长的三目运算符。如果超过 3 层请抽成函数,并写清楚注释。
#### 1.5.9 this 的转换命名
对上下文 this 的引用只能使用’self’来命名
#### 1.5.10 慎用 console.log
因 console.log 大量使用会有性能问题,所以在非 webpack 项目中谨慎使用 log 功能
# 二、Vue 项目规范
### (一) Vue 编码基础
vue 项目规范以 Vue 官方规范 (https://cn.vuejs.org/v2/style-guide/) 中的 A 规范为基础,在其上面进行项目开发,故所有代码均遵守该规范。
> 请仔仔细细阅读 Vue 官方规范,切记,此为第一步。
#### 2.1.1. 组件规范
##### 1) 组件名为多个单词。
组件名应该始终是多个单词组成(大于等于 2),且命名规范为`KebabCase`格式。
这样做可以避免跟现有的以及未来的 HTML 元素相冲突,因为所有的 HTML 元素名称都是单个单词的。
正例:
```
export default {
name: 'TodoItem'
// ...
};
```
反例:
```
export default {
name: 'Todo',
// ...
}
export default {
name: 'todo-item',
// ...
}
```
##### 2) 组件文件名为 pascal-case 格式
正例:
```
components/
|- my-component.vue
```
反例:
```
components/
|- myComponent.vue
|- MyComponent.vue
```
##### 3) 基础组件文件名为 base 开头,使用完整单词而不是缩写。
正例:
```
components/
|- base-button.vue
|- base-table.vue
|- base-icon.vue
```
反例:
```
components/
|- MyButton.vue
|- VueTable.vue
|- Icon.vue
```
##### 4) 和父组件紧密耦合的子组件应该以父组件名作为前缀命名
正例:
```
components/
|- todo-list.vue
|- todo-list-item.vue
|- todo-list-item-button.vue
|- user-profile-options.vue (完整单词)
```
反例:
```
components/
|- TodoList.vue
|- TodoItem.vue
|- TodoButton.vue
|- UProfOpts.vue (使用了缩写)
```
##### 5) 在 Template 模版中使用组件,应使用 PascalCase 模式,并且使用自闭合组件。
正例:
```
<!-- 在单文件组件、字符串模板和 JSX 中 -->
<MyComponent />
<Row><table :column="data"/></Row>
```
反例:
```
<my-component /> <row><table :column="data"/></row>
```
##### 6) 组件的 data 必须是一个函数
当在组件中使用 data 属性的时候 (除了 new Vue 外的任何地方),它的值必须是返回一个对象的函数。 因为如果直接是一个对象的话,子组件之间的属性值会互相影响。
正例:
```
export default {
data () {
return {
name: 'jack'
}
}
}
```
反例:
```
export default {
data: {
name: 'jack'
}
}
```
##### 7) Prop 定义应该尽量详细
- 必须使用 camelCase 驼峰命名
- 必须指定类型
- 必须加上注释,表明其含义
- 必须加上 required 或者 default,两者二选其一
- 如果有业务需要,必须加上 validator 验证
正例:
```
props: {
// 组件状态,用于控制组件的颜色
status: {
type: String,
required: true,
validator: function (value) {
return [
'succ',
'info',
'error'
].indexOf(value) !== -1
}
},
// 用户级别,用于显示皇冠个数
userLevel:{
type: String,
required: true
}
}
```
##### 8) 为组件样式设置作用域
正例:
```
<template>
<button class="btn btn-close">X</button>
</template>
<!-- 使用 `scoped` 特性 -->
<style scoped>
.btn-close {
background-color: red;
}
</style>
```
反例:
```
<template>
<button class="btn btn-close">X</button>
</template>
<!-- 没有使用 `scoped` 特性 -->
<style>
.btn-close {
background-color: red;
}
</style>
```
##### 9) 如果特性元素较多,应该主动换行。
正例:
```
<MyComponent foo="a" bar="b" baz="c"
foo="a" bar="b" baz="c"
foo="a" bar="b" baz="c"
/>
```
反例:
```
<MyComponent foo="a" bar="b" baz="c" foo="a" bar="b" baz="c" foo="a" bar="b" baz="c" foo="a" bar="b" baz="c"/>
```
#### 2.1.2. 模板中使用简单的表达式
组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。复杂表达式会让你的模板变得不那么声明式。我们应该尽量描述应该出现的是什么,而非如何计算那个值。而且计算属性和方法使得代码可以重用。
正例:
```
<template>
<p>{{ normalizedFullName }}</p>
</template>
// 复杂表达式已经移入一个计算属性
computed: {
normalizedFullName: function () {
return this.fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}
}
```
反例:
```
<template>
<p>
{{
fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}}
</p>
</template>
```
#### 2.1.3 指令都使用缩写形式
指令推荐都使用缩写形式,(用 : 表示 v-bind: 、用 @ 表示 v-on: 和用 # 表示 v-slot:)
正例:
```
<input
@input="onInput"
@focus="onFocus"
>
```
反例:
```
<input
v-on:input="onInput"
@focus="onFocus"
>
```
#### 2.1.4 标签顺序保持一致
单文件组件应该总是让标签顺序保持为 `
正例:
```
<template>...</template>
<script>...</script>
<style>...</style>
```
反例:
```
<template>...</template>
<style>...</style>
<script>...</script>
```
#### 2.1.5 必须为 v-for 设置键值 key
#### 2.1.6 v-show 与 v-if 选择
如果运行时,需要非常频繁地切换,使用 v-show ;如果在运行时,条件很少改变,使用 v-if。
#### 2.1.7 script 标签内部结构顺序
components > props > data > computed > watch > filter > 钩子函数(钩子函数按其执行顺序) > methods
#### 2.1.8 Vue Router 规范
##### 1) 页面跳转数据传递使用路由参数
页面跳转,例如 A 页面跳转到 B 页面,需要将 A 页面的数据传递到 B 页面,推荐使用 路由参数进行传参,而不是将需要传递的数据保存 vuex,然后在 B 页面取出 vuex 的数据,因为如果在 B 页面刷新会导致 vuex 数据丢失,导致 B 页面无法正常显示数据。
正例:
```
let id = ' 123';
this.$router.push({ name: 'userCenter', query: { id: id } });
```
##### 2) 使用路由懒加载(延迟加载)机制
```
{
path: '/uploadAttachment',
name: 'uploadAttachment',
meta: {
title: '上传附件'
},
component: () => import('@/view/components/uploadAttachment/index.vue')
},
```
##### 3) router 中的命名规范
path、childrenPoints 命名规范采用`kebab-case`命名规范(尽量vue文件的目录结构保持一致,因为目录、文件名都是`kebab-case`,这样很方便找到对应的文件)
name 命名规范采用`KebabCase`命名规范且和component组件名保持一致!(因为要保持keep-alive特性,keep-alive按照component的name进行缓存,所以两者必须高度保持一致)
```
// 动态加载
export const reload = [
{
path: '/reload',
name: 'reload',
component: Main,
meta: {
title: '动态加载',
icon: 'icon iconfont'
},
children: [
{
path: '/reload/smart-reload-list',
name: 'SmartReloadList',
meta: {
title: 'SmartReload',
childrenPoints: [
{
title: '查询',
name: 'smart-reload-search'
},
{
title: '执行reload',
name: 'smart-reload-update'
},
{
title: '查看执行结果',
name: 'smart-reload-result'
}
]
},
component: () =>
import('@/views/reload/smart-reload/smart-reload-list.vue')
}
]
}
];
```
##### 4) router 中的 path 命名规范
path除了采用`kebab-case`命名规范以外,必须以 / 开头,即使是children里的path也要以 / 开头。如下示例
-
目的:
经常有这样的场景:某个页面有问题,要立刻找到这个vue文件,如果不用以/开头,path为parent和children组成的,可能经常需要在router文件里搜索多次才能找到,而如果以/开头,则能立刻搜索到对应的组件
*
```
{
path: '/file',
name: 'File',
component: Main,
meta: {
title: '文件服务',
icon: 'ios-cloud-upload'
},
children: [
{
path: '/file/file-list',
name: 'FileList',
component: () => import('@/views/file/file-list.vue')
},
{
path: '/file/file-add',
name: 'FileAdd',
component: () => import('@/views/file/file-add.vue')
},
{
path: '/file/file-update',
name: 'FileUpdate',
component: () => import('@/views/file/file-update.vue')
}
]
}
```
### (二) Vue 项目目录规范
#### 2.2.1 基础
vue 项目中的所有命名一定要与后端命名统一。
比如权限:后端 privilege, 前端无论 router , store, api 等都必须使用 privielege 单词!
#### 2.2.2 使用 Vue-cli 脚手架
使用 vue-cli3 来初始化项目,项目名按照上面的命名规范。
#### 2.2.3 目录说明
目录名按照上面的命名规范,其中 components 组件用大写驼峰,其余除 components 组件目录外的所有目录均使用 kebab-case 命名。
```
src 源码目录
|-- api 所有api接口
|-- assets 静态资源,images, icons, styles等
|-- components 公用组件
|-- config 配置信息
|-- constants 常量信息,项目所有Enum, 全局常量等
|-- directives 自定义指令
|-- filters 过滤器,全局工具
|-- datas 模拟数据,临时存放
|-- lib 外部引用的插件存放及修改文件
|-- mock 模拟接口,临时存放
|-- plugins 插件,全局使用
|-- router 路由,统一管理
|-- store vuex, 统一管理
|-- themes 自定义样式主题
|-- views 视图目录
| |-- role role模块名
| |-- |-- role-list.vue role列表页面
| |-- |-- role-add.vue role新建页面
| |-- |-- role-update.vue role更新页面
| |-- |-- index.less role模块样式
| |-- |-- components role模块通用组件文件夹
| |-- employee employee模块
```
##### 1) api 目录
- 文件、变量命名要与后端保持一致。
- 此目录对应后端 API 接口,按照后端一个 controller 一个 api js 文件。若项目较大时,可以按照业务划分子目录,并与后端保持一致。
- api 中的方法名字要与后端 api url 尽量保持语义高度一致性。
- 对于 api 中的每个方法要添加注释,注释与后端 swagger 文档保持一致。
正例:
后端 url: EmployeeController.java
```
/employee/add
/employee/delete/{id}
/employee/update
```
前端: employee.js
```
// 添加员工
addEmployee: (data) => {
return postAxios('/employee/add', data)
},
// 更新员工信息
updateEmployee: (data) => {
return postAxios('/employee/update', data)
},
// 删除员工
deleteEmployee: (employeeId) => {
return postAxios('/employee/delete/' + employeeId)
},
```
##### 2) assets 目录
assets 为静态资源,里面存放 images, styles, icons 等静态资源,静态资源命名格式为 kebab-case
```
|assets
|-- icons
|-- images
| |-- background-color.png
| |-- upload-header.png
|-- styles
```
##### 3) components 目录
此目录应按照组件进行目录划分,目录命名为 KebabCase,组件命名规则也为 KebabCase
```
|components
|-- error-log
| |-- index.vue
| |-- index.less
|-- markdown-editor
| |-- index.vue
| |-- index.js
|-- kebab-case
```
##### 4) constants 目录
此目录存放项目所有常量,如果常量在 vue 中使用,请使用 vue-enum 插件([https://www.npmjs.com/package/vue-enum](https://www.npmjs.com/package/vue-enum))
目录结构:
```
|constants
|-- index.js
|-- role.js
|-- employee.js
```
例子: employee.js
```
export const EMPLOYEE_STATUS = {
NORMAL: {
value: 1,
desc: '正常'
},
DISABLED: {
value: 1,
desc: '禁用'
},
DELETED: {
value: 2,
desc: '已删除'
}
};
export const EMPLOYEE_ACCOUNT_TYPE = {
QQ: {
value: 1,
desc: 'QQ登录'
},
WECHAT: {
value: 2,
desc: '微信登录'
},
DINGDING: {
value: 3,
desc: '钉钉登录'
},
USERNAME: {
value: 4,
desc: '用户名密码登录'
}
};
export default {
EMPLOYEE_STATUS,
EMPLOYEE_ACCOUNT_TYPE
};
```
##### 5) router 与 store 目录
这两个目录一定要将业务进行拆分,不能放到一个 js 文件里。
router 尽量按照 views 中的结构保持一致
store 按照业务进行拆分不同的 js 文件
##### 6) views 目录
- 命名要与后端、router、api 等保持一致
- components 中组件要使用 PascalCase 规则
```
|-- views 视图目录
| |-- role role模块名
| | |-- role-list.vue role列表页面
| | |-- role-add.vue role新建页面
| | |-- role-update.vue role更新页面
| | |-- index.less role模块样式
| | |-- components role模块通用组件文件夹
| | | |-- role-header.vue role头部组件
| | | |-- role-modal.vue role弹出框组件
| |-- employee employee模块
| |-- behavior-log 行为日志log模块
| |-- code-generator 代码生成器模块
```
#### 2.2.4 注释说明
整理必须加注释的地方
- 公共组件使用说明
- api 目录的接口 js 文件必须加注释
- store 中的 state, mutation, action 等必须加注释
- vue 文件中的 template 必须加注释,若文件较大添加 start end 注释
- vue 文件的 methods,每个 method 必须添加注释
- vue 文件的 data, 非常见单词要加注释
#### 2.2.5 其他
##### 1) 尽量不要手动操作 DOM
因使用 vue 框架,所以在项目开发中尽量使用 vue 的数据驱动更新 DOM,尽量(不到万不得已)不要手动操作 DOM,包括:增删改 dom 元素、以及更改样式、添加事件等。
##### 2) 删除无用代码
因使用了 git/svn 等代码版本工具,对于无用代码必须及时删除,例如:一些调试的 console 语句、无用的弃用功能代码。
# Java开发规范
# 1. 命名规范
- class、interface、enum使用大驼峰,例如:“WxUser”
- interface命名以“I”为前缀,代表接口,例如:“IUserService”
- 接口实现类命名统一使用后缀impl,例如:”UserImpl“
- 包命名使用全小写
- 变量、方法、参数名等使用小驼峰,例如:“getUserInfo”
- 常量统一使用大写,不同单词间使用“_”连接,例如:“MAX_VALUE”
- JavaBean命名,统一后缀使用大写。例如:“UserInfoBO、PageVO、UserDTO”等。
- MVC各层命名示例
- entity——User
- mapper/dao——UserMapper/UserDao
- service——IUserService
- 实现类——UserServiceImpl
- controller——UserController
详细见《上海信睿JavaWeb开发规范.pdf》
# 2. 开发业务规范
### 2.1. IDEA阿里巴巴代码检查插件
推荐开发前在IDEA中下载阿里巴巴代码检查插件
打开IDEA,File-> Setteings->Plugins->Browse Repositories,在Browse Repositories搜索栏搜索Alibaba,然后安装Alibaba Java Coding Guidelines
下载本地zip文件,下载地址:Alibaba Java Coding Guidelines - IntelliJ IDEs Plugin | Marketplace
下载版本 Alibaba Java Coding Guidelines 2.1.1
打开IDEA,File->Settings->Plugin->Install plugin from disk,选择刚才自己下载插件zip包的地址
### 2. 2工具类封装
- 工具类位置,推荐封装在utils下
- 通用工具类封装在common模块下
- 和某个模块相关业务的工具类,封装在相关模块下
- 工具类推荐封装成static静态方法(有的不能不强求,比如需要bean注册)
### 2.3. 配置类
- 配置类位置,推荐封装在config下
- 通用配置类封装在common模块下
- 和某个模块相关业务的配置类,封装在相关模块下
- 配置类使用配置方式
- 推荐使用Java配置类
- 不推荐使用xml配置(日志配置除外)
- 推荐配置参数写在yml中进行读取
- 大量的配置读取,推荐写Properties类。可以省去大量属性的@Value读取
```java
@Data
@Configuration // 表示为配置类,注册到spring bean容器中
@ConfigurationProperties(prefix = "jwt") // 读取的yml配置的公共前缀
public class SecurityProperties {
// 属性
}
```
### 2.4. SpringBoot
- 采用配置类使用yml文件,更好的层级结构
- 推荐配置开发环境、测试环境、生成环境的配置文件。在不同环境下使用不同的配置文件
![image.png](https://cdn.nlark.com/yuque/0/2022/png/240791/1661784525655-fb4df49a-7783-4fc3-bc2e-6591899c21fe.png#clientId=ub895adca-d1a8-4&crop=0&crop=0&crop=1&crop=1&id=yUpCI&name=image.png&originHeight=194&originWidth=348&originalType=binary&ratio=1&rotation=0&showTitle=false&size=11247&status=done&style=none&taskId=ua5554774-75eb-401d-958f-fdd1fbd8285&title=)
### 2.5.注释规范
- **所有class、interface、enum等强制在类头部加注释**
- 注释方式:javadoc注释
- 注释内容
- 功能描述(description)
- 作者(@author)
- 日期(@Date)
- 注释模板
```java
/**
* description:对返回前端数据进行封装
*
* @author sinra
* Date: 2020/7/9 22:09
**/
@Data
public class ResponseResult<T> {
// ...
}
```
- **所有成员变量,推荐添加注释**
- 注释方式:javadoc注释
- 注释模板
```
/**
* 方式一:
* 状态码
*/
private Integer code;
/** 方式二:状态信息说明 */
private String message;
```
- **所有方法,强制添加注释**
- 注释内容:
- 功能描述(description)
- 参数信息(@param)
- 返回值信息(@return)
- 作者(@author)(推荐,可知道方法谁写的,方便维护)
- 日期(@Date)(推荐,可知道方法大致是在什么时候写的)
- 注释模板
```java
/**
* description: 接口调用成功,返回枚举中自定义的状态码及数据
*
* @param responseEnum 自定义枚举 状态码和信息
* @param data 返回数据
* @return 枚举中自定义的状态码及数据
* @author sinra
* Date: 2020/7/10 19:57
*/
public static <E> ResponseResult<E> ok ( ResponseEnum responseEnum, E data ) {
return new ResponseResult<>(responseEnum, data);
}
123456789101112
```
- **业务注释**
- 业务中多写注释,方便开发和维护,养成良好习惯
- 一块业务使用块级注释
- 一行代码使用行级注释
# 3. 日志规范
SLF4J 是门面模式的日志框架,有利于维护和各个类的日志处理方式统一,并且可以在保证不修改代码的情况下,很方便的实现底层日志框架的更换。
### 3.1 导入日志
```java
// 方式一
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger log = LoggerFactory.getLogger(User.class);
// 方式二
//采用lombok的@Slf4j注解
```
### 3.2 建议使用参数占位{}
使用大括号{}来作为日志中的占位符,比于使用+操作符,更加优雅简洁。并且,**相对于反例**,使用占位符仅是替换动作,可以有效提升性能。
```java
// 正例
log.info("该用户是会员,id: {} name : {} ", id, name);
// 反例
log.info("该用户是会员,id: " + id + " name: " + name);
```
### 3.3 不要使用e.printStackTrace()
- e.printStackTrace()打印出的堆栈日志跟业务代码日志是交错混合在一起的,通常排查异常日志不太方便。
- e.printStackTrace()语句产生的字符串记录的是堆栈信息,如果信息太长太多,字符串常量池所在的内存空间一旦被占满,就没空间进行其它操作了,大量其它的线程就会中止,等待内存空间的释放,相互等待,等内存,锁住了,整个应用就挂掉了。
```java
// 正例
try{
// 业务代码处理
}catch(Exception e){
log.error("你的程序有异常啦",e);
}
// 反例
try{
// 业务代码处理
}catch(Exception e){
e.printStackTrace();
}
```
### 3.4 异常日志不要只打一半,要输出全部错误信息
```java
// 正例
try {
//业务代码处理
} catch (Exception e) {
// 错误
log.error('你的程序有异常啦', e);
}
// 反例1,异常e都没有打印出来,所以压根不知道出了什么类型的异常。
try {
//业务代码处理
} catch (Exception e) {
// 错误
log.error('你的程序有异常啦');
}
//反例2,e.getMessage()不会记录详细的堆栈异常信息,只会记录错误基本描述信息,不利于排查问题。
try {
//业务代码处理
} catch (Exception e) {
// 错误
log.error('你的程序有异常啦', e.getMessage());
}
```
### 3.5 不要记录了异常,又抛出异常
- 这样实现的话,通常会把栈信息打印两次。这是因为捕获了MyException异常的地方,还会再打印一次。
- 这样的日志记录,或者包装后再抛出去,不要同时使用!否则日志看起来会很迷惑。
```java
log.error("IO exception", e);
throw new MyException(e);
```
### 3.6 核心功能模块,建议打印较完整的日志
如果核心或者逻辑复杂的代码,建议添加详细的注释,以及较详细的日志。
# 4. 第三方接口交互规范
**关键细节(附表一)**
| 关键细节 | 事项 | 备注 |
| --- | --- | --- |
| 字段内容 | 双方确定需要提供什么字段、需要获取哪些字段 |
|
| 接口版本 | 接口版本规范,url中 /v1/xxx,还是header中 verison=v1,以及协商版本具体规范细节 |
|
| 大量数据 | 分页返回 |
|
| 异常处理 | 定义错误码,以及其对应的相应操作,有什么兜底补偿方案没 |
|
| 调用方式 | 主动拉取还是被动等待推送 |
|
| 通信协议 | Restful、Webservice、MQ、Websocket等 | 一般建议Restful |
| 报文协议 | json、yaml、xml、自定义等 | 一般建议Json |
| 接口方式 | 同步接口还是异步接口 |
|
| 接口安全 | Oauth2.0 sign token等,注意内外网、以及业务的保密级别 |
|
| 幂等性 | 确保双方接口是否都是幂等的,防止重复提交 |
|
| 重试机制 | 一定要确认是否需要接口调用失败后的重试机制,保证数据传输的最终一致性
重试机制包括实时重试调用:指定次数 + 调用失败持久化,数据库定时任务重试 |
|
| 接口文档 | 要有详尽的说明和丰富的示例代码 |
|
### 4.1 提供给第三方系统的接口
- 要明确接口定义,确认对接双方甚至多方所需数据以及具体字段。
- 接口的接入参数一定要打日志记录,输出数据看情况打日志,对于变动的数据打上日志做记录。
- 日志要包含调用时间、错误原因、json数据(如果过长则记录关键字段)。
- 接口如果有大规模的资源占用要考虑对系统本身的影响,保证系统的正常运行。
- 接口的设计对于敏感数据要谨慎处理,要保证对外数据的安全性。
- 接口编写在关键代码处一定要打日志,以便监控接口运行情况以及发现错误和排除故障。
- 对外接口要形成API文档,文档包含请求方式、请求路径、入参、返回结果以及入参示例。
- 接口入参必填字段要做必填校验,防止null报错。
- 接口返回的状态码标准在文档中标明。如果是错误状态码要返回错误信息。
- 对于有幂等性要求的接口要提供查询接口,将调取的幂等性接口的结果返回。
### 4.2 调用第三方系统的接口
- 要明确调取目的、数据以及具体字段对应关系。
- 对接前尽量了解相关细节(附表一)。
- 调取第三方接口要有异常补偿机制。
- 接口调用后出现异常,记录下该方法调用的详细日志到数据库表中。
- 尝试用AOP异常捕捉的方式将补偿代码从业务代码中解耦出来处理。
- 多次调用仍然失败要记录数据以后后期人工处理。
- 补偿机制要考虑是否有幂等性,多次调用是否会对对方系统产生不同结果的影响,如果有则需要调用验证接口以验证补偿是否成功。
- 调取第三方接口字段拉平机制,可以考虑使用@JSONField注解等方式拉平2个系统之间的不同的字段值。
- 拉取数据对于一些字段值的转换,如果是固定字典关系可以建立枚举进行转换,如果经常变动的值则需要第三方给出数据接口拉取对应关系数据。
- 调用接口回调参数要有日志记录。
- 日志要包含接收时间、错误原因、json数据(如果过长则记录关键字段)。
# Git仓库规范
*不允许将公司级项目创建在私人账号目录下,例如:zhangsan/mdm*
# 代码仓库创建
在GitLab上先按项目建组,组里根据实际情况(例如按前、后端)分别建立Project
- 创建项目组Group按系统的英文描述命名,中间如需分隔符,一律用“-”
- 创建项目按项目具体负责的模块命名,中间如需分隔符,一律用“-”
- 每个项目有自己10-100字的描述,用于说明这个仓库是做什么的。
- 仓库由仓库Owner(或GroupOwner)负责,权限也由其分配。
- 每个项目都需要README.md文件,用于描述这个仓库相关的一些信息。
- 除文档说明类型仓库,所有代码仓库都需要有.gitignore文件,根据项目种类不同设定
参考示例:[http://www.shxrtech.com:8081/example-group](http://www.shxrtech.com:8081/example-group)
# 代码评审规范
## 前言
**Code Review 目的**
- 保证代码可读性,一致性。
- 代码层面减少bug,最基本缺少控制判断、异常处理。
- 减少重复代码(新人很容易多个轮子),比如日期处理函数,common有。自己也写,utils有,service也有,导致多处重复。
- 知识共享**+**设计讨论。
# CR模板
[xxxx项目_代码检查报告_20220828.xls](https://www.yuque.com/attachments/yuque/0/2022/xls/240791/1661825366155-54348cf1-e443-4dba-8d7a-581b4f6d3941.xls?_lake_card=%7B%22src%22%3A%22https%3A%2F%2Fwww.yuque.com%2Fattachments%2Fyuque%2F0%2F2022%2Fxls%2F240791%2F1661825366155-54348cf1-e443-4dba-8d7a-581b4f6d3941.xls%22%2C%22name%22%3A%22xxxx%E9%A1%B9%E7%9B%AE_%E4%BB%A3%E7%A0%81%E6%A3%80%E6%9F%A5%E6%8A%A5%E5%91%8A_20220828.xls%22%2C%22size%22%3A59392%2C%22type%22%3A%22application%2Fvnd.ms-excel%22%2C%22ext%22%3A%22xls%22%2C%22source%22%3A%22%22%2C%22status%22%3A%22done%22%2C%22mode%22%3A%22title%22%2C%22download%22%3Atrue%2C%22taskId%22%3A%22u6f811eab-45a3-41b0-9e5a-d30cfe6c3e7%22%2C%22taskType%22%3A%22upload%22%2C%22__spacing%22%3A%22both%22%2C%22id%22%3A%22iqKtN%22%2C%22margin%22%3A%7B%22top%22%3Atrue%2C%22bottom%22%3Atrue%7D%2C%22card%22%3A%22file%22%7D)
# 分支管理规范
# 1. 发布主分支(master)
- 每个代码库有且仅有一个主分支 master。所有提供给用户使用的正式版本,都在这个主分支上发布。
- master 分支仅用于发布正式版本,同时需确保主分支的任何内容都是可部署的。并且只允许对 master 进行其他分支的合并和创建标记操作,不能单独在 master 分支上进行提交。
# 2.开发主分支(develop)
- develop 分支是进行开发的基础分支,其他的短特性分支是基于develop分支切分出来的,当开始一个新的功能分支时,它将是开发的基础。
- 新功能的开发分支会合并在develop分支中,等待被整合到 master 分支中。
# 3. 功能分支(feature)
- feature 分支为开发某个功能点而创建。
- 完成功能点的开发后,feature 分支的最新内容部署 test 环境进行功能测试验收。功能点测试完成后再合并入 develop分支,并删除 feature 分支。
# 4. 热修复分支(hotfix)
- 正式发布以后,出现 Bug 。这时就需要创建一个 hotfix分支 ,进行 Bug 热修复,hotfix是基于master分支进行切分的,完成会合并入master分支,再合并到develop分支。
- 分支的命名格式为hotfix-[新版本号码],例如hotfix-0.1.1。
- 漏洞修复后需要为hotfix 分支制作一个新的修订号版本标记。最后,根据实际情况可选的合并入 master 分支,再合并到develop分支,并删除 hotfix 分支。
**仓库中存在两种长期分支:master和develop。master中存放对外发布的版本,只有稳定的发布版本才会合并到master中。develop用于日常开发,存放最新的开发版本。**
**二种临时分支:feature,hotfix,仅仅只是临时存在的,根据需要来创建,此类分支完成了自己的任务之后就会被删除掉。**
# 分支命名规约
| 前缀 | 含义 |
| --- | --- |
| master | 主分支,可用的、稳定的、可直接发布的版本 |
| develop | 开发主分支,最新的代码分支 |
| feature-** | 功能开发分支 |
| hotfix-** | 已发布bug修复分支 |
## 版本号规范
版本格式:主版本号.次版本号.修订号,版本号递增规则如下:
1.主版本号:当你做了不兼容的 API 修改。
2.次版本号:当你做了向下兼容的功能性新增。
3.修订号:当你做了向下兼容的问题修正。
先行版本号及版本编译信息可以加到“主版本号.次版本号.修订号”的后面,作为延伸。
# 环境管理规范
项目常用的几个环境:开发环境(DEV)、测试环境(TEST)、用户接受度测试环境(UAT)、生产环境(PROD)。根据各项目情况而定多数项目最少需要3个环境进行实际开发。
# DEV环境
开发人员或者开发团队的工作环境,可以根据开发的需求随时将变更更新在环境当中用于测试,可以是开发人员的本地环境,也可以是团队统一的环境,此环境必须与其他环境和资源严格隔离。
# TEST环境
该环境用于测试所有开发人员的代码进行整合之后运行环境,供测试人员使用。
# UAT环境
UAT环境主要是用来作为客户验证测试的环境。UAT环境应尽可能多地模拟生产环境,也可以兼作演示、培训用环境。
# PROD环境
即正式环境,主要用于生产使用。
[
](https://blog.csdn.net/zhengide/article/details/104616144)
# JDK安装手册
## Linux系统下安装方式
- **首先查看系统中是否已安装JDK**
:::info
[root@VM-12-6-centos software]# java -version
:::
显示如下:
:::info
openjdk version "1.8.0_102"
OpenJDK Runtime Environment(build 1.8.0_102-b14)
OpenJDK 64-Bit Server VM(build 25.102-b14, mixed mode)
:::
- **卸载已安装的**
首先检测安装包:
:::info
[root@VM-12-6-centos software]# rpm -qa | grep java
:::
显示如下:
:::info
java-1.7.0-openjdk-1.7.0.111-2.6.7.8.el7.x86_64
python-javapackages-3.4.1-11.el7.noarch
tzdata-java-2016g-2.el7.noarch
javapackages-tools-3.4.1-11.el7.noarch
java-1.8.0-openjdk-1.8.0.102-4.b14.el7.x86_64
java-1.8.0-openjdk-headless-1.8.0.102-4.b14.el7.x86_64
java-1.7.0-openjdk-headless-1.7.0.111-2.6.7.8.el7.x86_64
:::
卸载:
:::info
[root@VM-12-6-centos software]# rpm -e --nodeps tzdata-java-2016g-2.el7.noarch
[root@VM-12-6-centos software]# rpm -e --nodeps java-1.7.0-openjdk-1.7.0.111- 2.6.7.8.el7.x86_64
[root@VM-12-6-centos software]# rpm -e --nodeps java-1.7.0-openjdk-headless-1.7.0.111-2.6.7.8.el7.x86_64
[root@VM-12-6-centos software]# rpm -e --nodeps java-1.8.0-openjdk-1.8.0.102-4.b14.el7.x86_64
[root@VM-12-6-centos software]# rpm -e --nodeps java-1.8.0-openjdk-headless-1.8.0.102-4.b14.el7.x86_64
:::
之后再次输入rpm -qa | grep java 查看卸载情况:
:::info
[root@VM-12-6-centos software]# rpm -qa | grep java
python-javapackages-3.4.1-11.el7.noarch
javapackages-tools-3.4.1-11.el7.noarch
:::
- **安装JDK**
首先到官网下载需要的JDK版本,也可以从[公司软件库](https://www.baidu.com)下载,在此省略此步骤
将jdk包上传到系统中指定的目录 **/opt/software**
创建JDK存放目录:
:::info
[root@VM-12-6-centos local]# mkdir /usr/local/java
:::
进入安装包目录:
:::info
[root@VM-12-6-centos local]# cd /opt/software
:::
解压jdk-8u161-linux-x64.tar.gz安装包到指定目录:
:::info
[root@VM-12-6-centos software]# tar -zxvf jdk-8u161-linux-x64.tar.gz -C /usr/local/java
:::
设置环境变量:
:::info
[root@VM-12-6-centos java]# vim /etc/profile
:::
在最后面添加:
:::info
export JAVA_HOME=/usr/local/java/jdk1.8.0_161
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
:::
记得保存噢! (1.使用vim编辑好文件后,按下esc键退出编辑状态; 2.输入冒号+wq字符,按下回车.)
执行profile文件:
:::info
[root@VM-12-6-centos java]# source /etc/profile
:::
这样可以使配置文件立即生效
- **检测JDK是否安装成功**
执行命令:
:::info
[root@VM-12-6-centos java]# java -version
:::
出现以下结果则JDK安装成功:
:::info
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)
:::
至此,JDK安装结束。
# Nginx安装手册
## 安装包下载
[http://nginx.org/en/download.html](http://nginx.org/en/download.html)
- **安装Nginx**
1. 安装依赖:
:::info
[root@VM-12-6-centos software]# yum -y install gcc zlib zlib-devel pcre pcre-devel openssl openssl-devel make
:::
2. 解压安装包并切换到文件夹中:
:::info
[root@VM-12-6-centos software]# tar -zxvf /opt/software/nginx-1.22.0.tar.gz
[root@VM-12-6-centos software]# cd nginx-1.22.0
:::
3. 开始执行编译、安装(一并安装SSL模块):
:::info
[root@VM-12-6-centos nginx-1.22.0]# ./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module
[root@VM-12-6-centos nginx-1.22.0]# make && make install
:::
4. 查看是否安装成功
:::info
[root@VM-12-6-centos nginx-1.22.0]# /usr/local/nginx/sbin
[root@VM-12-6-centos nginx-1.22.0]# ./nginx -V
:::
显示如下:
:::info
nginx version: nginx/1.22.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module
:::
安装结束。
- **配置环境变量**
1. 查看 nginx 版本,此时会发现报 bash:nginx: 未找到命令,需要我们手动配置打开环境变量的文件
:::info
[root@VM-12-6-centos nginx-1.22.0]# nginx -v
:::
显示如下:
:::info
bash: nginx: command not found...
:::
2. 编辑环境变量文件:
:::info
[root@VM-12-6-centos nginx-1.22.0]# vim /etc/profile
:::
行末加上自己的nginx安装目录下sbin目录的地址:
```shell
.... #前面省略
export PATH=$PATH:/usr/local/nginx/sbin
```
3. 重新加载环境:
:::info
[root@VM-12-6-centos nginx-1.22.0]# source /etc/profile
:::
4. 再次查看 nginx 版本
:::info
[root@iZuf68wpeyqmolhdab3bh0Z software]# nginx -v
:::
显示如下:
:::info
nginx version: nginx/nginx-1.22.0
:::
- **开机启动配置**
1. 先创建开机自启脚本:
:::info
[root@VM-12-6-centos software]# cd /etc/systemd/system
[root@VM-12-6-centos system]# vim nginx.service
:::
2. 内容复制到 vim 中:
```shell
[Unit]
Description=nginx service
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s quit
PrivateTmp=true
[Install]
WantedBy=multi-user.target
```
3. 服务命令:
:::info
**第一种方式启动**
**#启动nginx服****务**
cd /usr/local/nginx/sbin/
./nginx
**#查看运行状态**
ps aux | grep nginx
**#停止nginx服务**
./nginx –s stop
**#重启nginx服务**
./nginx –s reload
**#检查配置文件是否正确**
./nginx –t
**#查看nginx版本**
./nginx –v
**第二种基于配置开机启动模式启动**
**#设置开机自启动**
systemctl enable nginx
**#启动nginx服务**
systemctl start nginx.service
**#重新启动服务**
systemctl restart nginx.service
**#查看服务当前状态**
systemctl status nginx.service
**#停止开机自启动**
systemctl disable nginx.service
:::
4. 访问服务器IP
显示welcom to nginx 说明启动安装成功了,接下来可以通过编辑nginx.conf文件来进行项目的部署了。建议备份一下配置文件。
- **配置HTTPS**
证书可以自行到阿里云或者腾讯云申请免费的证书,并下载对应Nginx的证书
服务器 /usr/local/nginx/conf 下创建 cert 目录,并将证书放入该文件夹中
编辑Nginx配置文件:
:::info
[root@VM-12-6-centos software]# cd /usr/local/nginx/conf
[root@VM-12-6-centos conf]# vim nginx.conf
:::
在http代码块里添加如下配置:
```shell
server {
listen 80;
server_name xxx.com; #你的域名
rewrite ^(.*)$ https://$host$1 permanent; #把http的域名请求转成https
}
server {
listen 443;
server_name xxx.com;
ssl on;
ssl_certificate cert/xxxxxxxxxxxxxxx.pem; #证书文件路径
ssl_certificate_key cert/xxxxxxxxxxxxxxx.key; #证书文件路径
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!!
ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
#配置根路径(根据自身需求进行配置)
location / {
proxy_pass http://127.0.0.1:8080;
}
#配置后台业务路径(根据自身需求进行配置)
location /portal {
alias /usr/local/app/webapps/portal/;
index index.html index.htm;
}
}
```
- **常用配置**
```shell
nginx对上传文件大小有要求,默认1m,如果很大,还要适当调整上传超时时间。
1. client_max_body_size
限制请求体的大小,若超过所设定的大小,返回413错误。
client_header_timeout
读取请求头的超时时间,若超过所设定的大小,返回408错误。
3. client_body_timeout
读取请求实体的超时时间,若超过所设定的大小,返回413错误。
proxy_connect_timeout
http请求无法立即被容器(tomcat, netty等)处理,被放在nginx的待处理池中等待被处理。此参数为等待的最长时间,默认为60秒,官方推荐最长不要超过75秒。
proxy_read_timeout
http请求被容器(tomcat, netty等)处理后,nginx会等待处理结果,也就是容器返回的response。此参数即为服务器响应时间,默认60秒。
proxy_send_timeout
http请求被服务器处理完后,把数据传返回给Nginx的用时,默认60秒。
```
# Redis安装手册
Redis约定次版本号(即第一个小数点后的数字)为偶数的版本是稳定版(如2.8版、3.0版),奇数版本是非稳定版(如2.7版、2.9版),生产环境下一般需要使用稳定版本。
# 安装依赖
redis是由C语言开发,因此安装之前必须要确保服务器已经安装了gcc,可以通过如下命令查看机器是否安装:
:::info
gcc -v
:::
如果没有安装则通过以下命令安装:
:::info
yum install -y gcc
:::
# 下载安装包
访问查看需要的版本:[http://download.redis.io/releases](http://download.redis.io/releases)
:::info
**#安装包统一存放到/opt/software目录下,没有则进入/opt目录执行创建mkdir software创建**
cd /opt/software
wget http://download.redis.io/releases/[redis-6.2.6.tar.gz](http://download.redis.io/releases/redis-6.2.6.tar.gz)
:::
如果提示wget找不到通过一下命令安装:
:::info
yum -y install wget
:::
# 解压安装包并安装
解压安装包
:::info
tar xzf redis-6.2.6.tar.gz -C /usr/local
:::
进入解压目录并编译
:::info
**#进入解压目录**
cd redis-6.2.6
**#编译**
make
**#指定安装目录并进行安装**
make install PREFIX=/usr/local/redis-6.2.6
:::
# 启动Redis服务
通过守护进程方式启动
:::info
**#修改redis.conf**
cd /usr/local/redis-6.2.6
vim redis.conf
**# 修改内容如下:**
daemonize 的值从 no 修改成 yes
**#使用ESC键,并输入**
:wq
:::
启动服务
:::info
cd /usr/local/redis-6.2.6/bin
./redis-server ../redis.conf
:::
查看进程来确定redis是否启动成功
:::info
ps -ef |grep redis
:::
关闭服务
:::info
cd /usr/local/redis-6.2.6/bin
/redis-cli shutdown
:::
# 项目部署手册
# 1. 目的
为了保证系统稳定性运行,严格管理、规范实施,制定本项目部署和版本发布规范。
# 2. 项目部署环境
## 2.1 Spring Boot 项目
### 2.1.1 部署路径目录
- app --资源总目录
- fatjar  --项目Jar包目录
- tool --项目启动脚本目录
- logs --日志目录
- backup --备份目录
- tmp --临时目录
### 2.1.2 启动脚本定义
Linux:
```shell
#!/bin/bash
FAT_JAR_DIR=../fatjar/
APP_NAME=check-service*
APP_PATH=$FAT_JAR_DIR$APP_NAME
PROFILES_ACTIVE=test
if [ "$2" ]; then
PROFILES_ACTIVE=$2
fi
PID=$(ps -ef|grep $APP_NAME|grep -v grep|grep -v kill|awk '{print $2}')
case "$1" in
start)
if [ "$PID" ]; then
kill -9 "$PID"
echo kill $APP_NAME "$PID"
fi
java -jar $APP_PATH --spring.profiles.active="$PROFILES_ACTIVE" > /dev/null 2>&1 &
echo $APP_NAME is start at profiles "$PROFILES_ACTIVE"
;;
stop)
if [ -z "$PID" ]
then
echo $APP_NAME is already stopped
else
echo kill "$PID"
kill -9 "$PID"
echo $APP_NAME is stopped
fi
;;
status)
if [ -z "$PID" ]
then
echo $APP_NAME is already stopped
else
echo $APP_NAME is running
fi
;;
*)
echo "useing generator-boot.sh (start|stop|status)"
esac
```
:::info
**修改脚本参数参数:**
FAT_JAR_DIR:默认../fatjar/,一般不用调整
APP_NAME:Jar名称,例如:check-service-1.0.0.jar,可写成check-service*,但必须保证唯一,通过check-service*只能找到一个文件,如再出现check-service-biz-1.0.0.jar则会找到2个将存在问题
PROFILES_ACTIVE:项目环境,根据服务器是属于DEV/TEST/PORD进行调整
**如何启动, 停止, 以及查询服务的运行状态:**
./run-xxx.sh start //启动项目
./run-xxx.sh stop //停止项目
./run-xxx.sh status //查看项目状态
注意事项:
1. 如果当前服务器存在多个用户账号去启停程序,需要注意采用原始账号操作,否则可能会启动多个进程,操作程序错误。
1. 有特殊场景下会存在多个程序进程执行,可通过命令:ps -ef | grep java 查找到PID,再通过kill -9 PID 结束进程。
:::
## 2.2 Tomcat 项目
- Tomcat 安装略过
- Tomcat 同级创建backup目录,用于备份项目包
- 直接将 Web 项目文件拷贝到 webapps 目录中
## 2.3 Vue 项目
开发完的vue的项目 首先运行 以下命令 对项目进行打包
### **2.3.1 打包**
默认情况下,使用vue-cli创建的项目,package.json里的script应该已经配置了build指令,直接执行yarn build 或者 npm run build即可。
### **2.3.1 部署路径目录**
第一种方式:将vue打包后放在springboot项目的resource下的static文件夹下,将vue当成一个静态资源去访问,部署相对方便,能跟springboot项目一起被打成jar包,启动方便。
第二种方式:用ngnix去做代理,vue、springboot分开部署,分开部署不会相互影响。
通用情况下采用第二种方式,部署到nginx的html目录下。
**域名根目录部署**
比如我们希望项目部署到[http://shxrtech.com](https://link.zhihu.com/?target=http%3A//a.com/test)下,这样访问[http://shxrtech.com](https://link.zhihu.com/?target=http%3A//a.com/test)访问到的是项目的首页
```shell
这里给出的是示例,具体需要按自己项目来
server {
#端口
listen 8081;
#ip地址
server_name localhost;
#这里为项目访问的根路径,以及默认访问的文件
location / {
#将打包后的前端项目放到root设置的路径下
root html/cosco;
#这里默认即可
index index.html index.htm;
}
#请求代理配置到你后端启动的地址
location /api {
proxy_pass http://localhost:8080/api;
}
}
```
**非域名根路径部署**
有时候同一台服务器同一端口下可能会根据目录划分出多个不同的项目,比如我们希望项目部署到[http://shxrtech.com/test](https://link.zhihu.com/?target=http%3A//a.com/test)下,这样访问[http://shxrtech.com/test](https://link.zhihu.com/?target=http%3A//a.com/test)访问到的是项目的首页,而非test前缀的地址会访问到其它项目。此时需要修改nginx配置以及Vue打包配置。
```shell
这里给出的是示例,具体需要按自己项目来
server {
#端口
listen 8081;
#ip地址
server_name localhost;
#这里为项目访问的根路径,以及默认访问的文件
location / {
#将打包后的前端项目放到root设置的路径下
root html/cosco;
#这里默认即可
index index.html index.htm;
}
location /test {
#将打包后的前端项目放到root设置的路径下
root html/test;
#这里默认即可
index index.html index.htm;
}
#请求代理配置到你后端启动的地址
location /api {
proxy_pass http://localhost:8080/api;
}
}
```
**最后就是nginx修改配置一定要重启!!**
:::info
**#进入nginx安装目录**
cd /usr/local/nginx/sbin/
**#检查配置文件是否正确**
./nginx –t
**#重启nginx服务**
./nginx –s reload
:::
### **2.3.1 **解决刷新路由404问题
Vue项目采用了history的路由方式后打包出现404
解决问题的办法:
1. 将路由模式改为hash
1. 修改nginx配置
```shell
location / {
root ...
index ...
try_files $uri $uri/ /index.html; ---解决页面刷新404问题
}
```
# 3. 部署事项
## 3.1 部署前期
- 测试环境应与生产环境采用相同的操作系统、数据库和服务器版本
- 合并代码到预发布分支,部署到测试环境进行测试验证,源代码必须保持一致,能够分环境配置参数的项目必须采用配置文件
- 部署中涉及到第三方配合的,需要制定上线计划,上线计划应该清晰地表明执行步骤和负责人
- 需要准备好回退计划
## 3.2 部署中
### 3.2.1 单节点发布:
- 编译---从git的master分支或指定tag拉取代码
- 上传---编译完成后的程序包上传到指定机器的目录下
- 停止---在指定服务器上停止当前需要更新的程序包
- 备份---在指定服务器上备份当前需要更新的程序包(必须要备份)
- 更新---在指定服务器上启动最新的程序包
### 3.2.2 多节点发布:
多节点部署是一种可以保证系统在不间断提供服务的情况下上线部署方式;
在系统升级的时候,先把集群中的节点A进行剔除,进行新版本的更新,此时集群中的节点B仍然在继续的提供服务;当节点A升级完毕,再把节点A添加到集群当中,然后在将节点B从集群中剔除进行升级,节点A进行提供服务,当节点B升级完毕后,再把节点B也恢复到负载列表中去。
### 3.2.3 数据库操作:
- 生产环境新增字段采用Alert 语句,详细记录到部署文件中。
- 涉及批量操作(含CURD)必须备份全表数据,规则采用:原表名_bakup_yyyymmdd,备份数据可根据时间周期选择性删除。
### 3.3 部署验证
- 服务启动验证,确保相关的服务均已启动。
- 检查日志中是否有错误信息
- 更新内容测试,对本次版本新增功能和修正BUG进行1次验证(部分无法验证的,在第二天进行观察日志输出是否正常)。
- 验证结果不达标,可选择回滚、现场修复、后期更新等方式。
- 项目部署完成或回滚后应及时通知项目负责人或客户此次发布相关结果。
- 上线完成后,更新归档上线文档
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