0%

写在开头:
1看这里的时候,请确保你已将熟悉JavaScript以及了解Vue的语法, Django的语法也略懂一二。
如果不是很了解,请点击这里查看学习文档VueDjango,否则下文可能有些不好理解。
2文章有点长 ,因为包含了一个Index.vue页面。
3第一次写长文章,所以排版很尴尬,请指正。

  1. 安装Vue环境
  2. 安装element-ui组件 使用其组件美化界面
1
npm i element-ui -S ||  npm install element-ui --save
1
2
3
4
5
main.js 
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI)
  1. 安装axios 使用其完成前端到后端的请求

由于axios 使用Vue.use(无效),所以要将其绑定在Vue原型上

1
npm install axios --save |  brew install axios --save
1
2
3
4
5
import axios from 'axios'

axios.defaults.baseURL = 'http://localhost:8000'

Vue.prototype.$axios = axios
  1. 安装Django及配置环境
  2. 配置mysql数据库,使用sqlite3的 跳过此步骤无需配置
1
2
3
4
5
6
7
8
9
10
11
settings.py
DATABASES = {
'default': { #
'ENGINE': 'django.db.backends.mysql', # 不同库有不同的殷勤
'NAME': 'python_use', # 使用的库名
'USER': 'root',
'PASSWORD': '',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}

配置完成后请查看django是否报错,不报错即连接成功

  1. 安装 pipdjango-cors-headers
1
2

pip install django-cors-headers
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
settings.py

INSTALLED_APPS = {
...
'corsheaders',
...
}


MIDDLEWARE = [
...

'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
...
]


CORS_ORIGIN_ALLOW_ALL = True





至此,已将Vue和Django安装并配置好,接下来写一个简单的CRUD操作。
请确认你的整个项目目录与此类似

![](Vue + Django/2064404-d3a828d4530715b4.png)

项目目录结构

以下使用的目录均为此图所示


  1. 配置路由
1
2
3
4
5
first/urls.py 
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'', include('crud.urls')),
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
crud/urls.py




from django.conf.urls import url
from . import views

urlpatterns = [
url('create/', views.create, name = 'create'),
url('read', views.read, name = 'read'),
url('update/', views.update, name = 'update'),
url('delete/', views.delete, name = 'delete'),
url('search', views.search, name = 'search')
]
  1. 创建models,即在数据库中创建表
1
2
3
4
5
from django.db import models
class Books ( models.Model ):
book_name = models.CharField( max_length = 255 )
book_price = models.DecimalField( max_digits = 5, decimal_places = 2 )
book_time = models.DateTimeField( '保存日期', auto_now_add = True )

Models创建完成后运行命令 将其应用到数据库中并创建表
如果不懂 请返回顶部阅读Django文档

1
2
python manage.py makemigrations
python manage.py migrate
  1. 编写views.py 完成增删改查的逻辑
1
2
3
4
5
6
7
8
9
10
11
12
# 1 获取前端传递来的参数
# 1.1 get方法发送的参数
request.GET['content']
# 1.2 post方法发送的参数
obj = json.loads(request.body)
name = obj['name']
# 2 由于使用Books.objects下的方法,获取到的数据为Query Set类型,
# 所以需要使用serializers.serialize("json", books)
# 将查询到的数据进行序列化,变成可读的对象。
# 3 向前端返回处理结果
return HttpResponse(json.dumps(res), content_type="application/json")
# 将res变成json字符串返回给前端。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

from __future__ import unicode_literals
from django.shortcuts import render
from django.http import HttpResponse
import json
from django.core import serializers
from django.utils import timezone
from crud.models import Books

def search(request):
content = request.GET['content']
try:
books = serializers.serialize("json",Books.objects.filter(book_name__contains=content))
res = {
"code": 200,
"data": books
}
print(books)
except Exception,e:
res = {
"code": 0,
"errMsg": e
}
return HttpResponse(json.dumps(res), content_type="application/json")

def create(request):
print('create')
obj = json.loads(request.body)
name = obj['name']
price = obj['price']
try:
book = Books(book_name=name, book_price=price, book_time=timezone.now())
book.save()
res = {
"code": 200,
}
except Exception,e:
res = {
"code": 0,
"errMsg": e
}
return HttpResponse(json.dumps(res), content_type="application/json")

def read(request):
print('read')
try:
res = {
"code": 200,
"data": serializers.serialize("json",Books.objects.filter())
}
except Exception,e:
res = {
"code": 0,
"errMsg": e
}
return HttpResponse(json.dumps(res), content_type="application/json")

def update(request):
print('update')
obj = json.loads(request.body)
pid = obj['id']
name = obj['name']
price = obj['price']
try:
Books.objects.filter(id=pid).update(book_price=price, book_name=name)
res = {
"code": 200
}
except Exception,e:
res = {
"code": 0,
"errMsg": e
}
return HttpResponse(json.dumps(res), content_type="application/json")

def delete(request):
print('delete')
obj = json.loads(request.body)
print(obj)
pid = obj['id']
try:
Books.objects.filter(id=pid).delete()
res = {
"code": 200
}
except Exception,e:
res = {
"code": 0,
"errMsg": e
}
return HttpResponse(json.dumps(res), content_type="application/json")

  1. 配置路由
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
frontend/src/router/index.js

import Vue from 'vue'
import Router from 'vue-router'
import Index from '@/components/Index'

Vue.use(Router)

export default new Router({
routes: [
{
path: '/',
name: 'index',
component: Index
}
]
})
  1. 编写路由中使用到的组件 与上面import所用名称和路径需要一致,请耐心看完注释。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21








this.$axios.get('/search', {
params: {
content: this.search
}
}).then(res => {
console.log(res)
})
this.$axios.post('/delete/', JSON.stringify(row)).then(res => {

console.log(res)


})

以下为Index.vue的全部页面,包含增删改查的基本操作,以及更改和新增时的弹出框:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
frontend/src/components/Index.vue
<template>
<div>
<el-button type="primary" round @click="handleShowCreate">增加书籍</el-button>
<el-input v-model="search" placeholder="请输入内容" style="width: 200px" @keyup.enter.native="handleSearch"/>
<el-button type="primary" round @click="handleSearch">搜索</el-button>
<el-table :data="booksData" height="250" border style="width: 600px; margin: 40px auto;" v-loading="loading">
<el-table-column
prop="book_name"
label="书名"
align="center"
width="200">
</el-table-column>
<el-table-column
prop="book_price"
label="价格"
align="center"
width="200">
</el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button
size="mini"
@click="handleUpdate(scope.$index, scope.row)">编辑</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog title="修改书籍" :visible.sync="dialogUpdateVisible">
<el-form :model="updateData">
<el-form-item label="书籍名称">
<el-input auto-complete="off" v-model="updateData.name"></el-input>
</el-form-item>
<el-form-item label="书籍价格">
<el-input-number v-model="updateData.price" :precision="2" :step="0.01" :max="9999"></el-input-number>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="handleCancel('dialogUpdateVisible')">Cancel</el-button>
<el-button type="primary" @click="handleConfirm('dialogUpdateVisible')">Submit</el-button>
</div>
</el-dialog>
<el-dialog title="增加书籍" :visible.sync="dialogCreateVisible">
<el-form :model="createData">
<el-form-item label="书籍名称">
<el-input auto-complete="off" v-model="createData.name"></el-input>
</el-form-item>
<el-form-item label="书籍价格">
<el-input-number v-model="createData.price" :precision="2" :step="0.01" :max="9999"></el-input-number>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="handleCancel('dialogCreateVisible')">Cancel</el-button>
<el-button type="primary" @click="handleCreate('dialogCreateVisible')">Submit</el-button>
</div>
</el-dialog>
</div>
</template>

<script>
export default {
name: 'index',
data () {
return {
search: '',
booksData: [],
oldData: {},
updateData: {},
createData: {
name: '',
price: 0
},
dialogUpdateVisible: false,
dialogCreateVisible: false,
loading: true
}
},
methods: {
handleShowCreate () {
this.dialogCreateVisible = true
},
handleCreate () {
if (this.createData.name === '') {
this.$message.error('please input book name')
return
}
if (this.createData.price === 0) {
this.$message.error('please input book price')
return
}
this.$axios.post('/create/', JSON.stringify(this.createData)).then(res => {
if (res.data.code === 200) {
this.$message.success(`create ${this.createData.name} success`)
this.dialogCreateVisible = false
this.handleRead()
} else {
this.$message.error("can't read books database")
}
})
console.log(this.createData)
},
handleRead () {
this.booksData = []
this.$axios.get('/read').then(res => {
this.loading = false
if (res.data.code === 200) {
let books = JSON.parse(res.data.data)
for (let i in books) {
books[i].fields.id = books[i].pk
books[i].fields.book_price = Number(books[i].fields.book_price)
this.booksData.push(books[i].fields)
}
console.log(this.booksData)
} else {
this.$message.console.error("can't read books database")
}
}).catch((res) => {
console.log(res)
})
},
handleUpdate (index, row) {
this.dialogUpdateVisible = true
this.updateData = Object.assign({}, {
id: row.id,
name: row.book_name,
price: row.book_price,
time: row.book_time
})
this.oldData = Object.assign({}, {
id: row.id,
name: row.book_name,
price: row.book_price,
time: row.book_time
})
},
handleDelete (index, row) {
this.$confirm(`are you sure to delete ${this.updateData.name} ?`, '', {
confirmButtonText: 'submit',
cancelButtonText: 'cancel',
type: 'warning'
}).then(() => {
this.$axios.post('/delete/', JSON.stringify(row)).then(res => {
if (res.data.code === 200) {
this.$message.success(`delete ${this.updateData.name} success`)
this.handleRead()
} else {
this.$message.error("can't read books database")
}
})
}).catch(() => {
this.$message.info('cancel delete')
})
},
handleCancel (arg) {
this.$message.info('cancel')
this[arg] = false
},
handleConfirm (arg) {
if (this.updateData.name === this.oldData.name && this.updateData.price === this.oldData.price) {
this.$message.error('please update something or cancel')
return
}
this[arg] = false
this.$axios.post('/update/', JSON.stringify(this.updateData)).then(res => {
if (res.data.code === 200) {
this.$message.success(`update ${this.updateData.name} success`)
this.handleRead()
} else {
this.$message.error("can't read books database")
}
})
},
handleSearch () {
this.$axios.get('search', {
params: {
content: this.search
}
}).then(res => {
if (res.data.code === 200) {
if (res.data.data && JSON.parse(res.data.data).length > 0) {
this.booksData = []
let books = JSON.parse(res.data.data)
for (let i in books) {
let obj = {
id: books[i].pk,
book_name: books[i].fields.book_name,
book_price: Number(books[i].fields.book_price),
book_time: books[i].fields.book_time
}
this.booksData.push(obj)
}
} else {
this.$message.error(`can't search contains of '${this.search}' in database`)
}
} else {
this.$message.error(`can't search books in database`)
}
})
}
},
mounted () {
this.handleRead()
}
}
</script>

到这里,一个增删改查基本操作的页面就写完了,如果哪里有问题可以留言指正。 git源码以上传, 没事可以star/fork 更新将在以下附注后增加。

https://github.com/RogersLei/django-vue


附注 :

  1. Vue添加事件所用到的修饰符:

    ![](Vue + Django/2064404-1aa984b701bf3e11.png)

    Vue事件绑定修饰符

  2. Django中模糊查询用到的语法:

YourModels.objects.filter(headline__contains=str)
字段名__contains / __icontains 忽略大小写

更多精彩内容,就在简书APP

“小礼物走一走,来简书关注我”

还没有人赞赏,支持一下

总资产23共写了2.2W字获得33个赞共22个粉丝

推荐阅读更多精彩内容

  • 一.前言 最近接手了一个项目,后端是django,前端是django自带的模板,用的是jinja2,写了一段时间发…

  • 组织文章借鉴 ——培训师的21项修炼 书籍结构:错误的案例情景重现-抛出问题,传道受业解惑也 我们假设一个场景,大…

  • 每天总是忙忙碌碌,感觉时间完全不够用,更不要说是学习了,可是忙忙碌碌到最后感觉收获也很小,就像大家说的,瞎忙活。…

  • 和姑姑聊起当时借钱给已故父亲治病时的场景,我依稀记得当时我和涛古,妈妈给厂里老板下跪借那三万块的场景。这辈子希望以…

本文整合Django和Vue.js  并引入elementUi 实现前后端分离项目环境

最终的成品是设计出一个ElementUi风格的页面可以添加和显示学生信息.

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/20210415104816822.png)

Django作为Python 三大Web框架之一,因其集成了大量的组件(例如: Models Admin Form 等等)而大受欢迎,但是他本身自带的template模板实在是有点弱.于是考虑整合Vue.js同时引入ElementUI 组件,可以更加快速高效的开发出美观实用的Web页面.

Python

本文版本:Python 3.5

安装教程: https://www.runoob.com/python3/python3-install.html

Pycharm

本文版本:2019.1.3

PyCharm 2019.1.3 (Community Edition)

安装教程:https://www.runoob.com/w3cnote/pycharm-windows-install.html

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/20210414104837104.png)

Django

本文版本:2.2.3

安装教程:https://www.runoob.com/django/django-install.html

node.js

本文版本:10.16.3

安装教程:https://www.runoob.com/nodejs/nodejs-install-setup.html

MySQL

本文版本: 8.0.13 for Win64

安装教程:https://www.runoob.com/mysql/mysql-install.html

本文的Pycharm为社区版,如果为专业版则字段Django项目的创建选项,创建项目将更加简单.

1.创建django项目:DjangoElementUI

创建文件夹E:\PycharmProjects:

在项目文件夹目录输入Windows 命令行如下

1
django-admin.py startproject DjangoElementUI

成功创建项目完成后文件夹结构如下图:

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/20210414135547501.png)

进入项目文件夹目录,在目录中输入命令

1
python manage.py runserver 0.0.0.0:8000

看到如下提示则为项目创建成功

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/20210414140242161.png)

在浏览器输入你服务器的 ip(这里我们输入本机 IP 地址: 127.0.0.1:8000) 及端口号,如果正常启动,输出结果如下:

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/2021041414041267.png)

2.数据库配置

Django 对各种数据库提供了很好的支持,包括:PostgreSQL、MySQL、SQLite、Oracle。

Django 为这些数据库提供了统一的调用API。 我们可以根据自己业务需求选择不同的数据库。

MySQL 是 Web 应用中最常用的数据库。

本文采用MySQL

第一次使用MySQL需要安装 MySQL驱动,在项目文件夹目录下执行以下命令安装:

1
pip install pymysql

Django无法直接创建数据库(只能操作到数据表层),我们需要手工创建MySQL数据库.

以下通过命令行创建 MySQL 数据库:Django_ElementUI

登录数据库:

数据库安装文件夹bin文件夹下输入命令

1
mysql -u root -p 

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/20210414143607555.png)

创建数据库:

1
create DATABASE Django_ElementUI DEFAULT CHARSET utf8;

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/20210414143542756.png)

Django配置数据库

在项目的 settings.py 文件中找到 DATABASES 配置项,将其信息修改为:

1
'ENGINE': 'django.db.backends.mysql',  'NAME': 'Django_ElementUI',  

在与 settings.py 同级目录下的 __init__.py 中引入模块和进行配置 (告诉 Django 使用 pymysql 模块连接 mysql 数据库)

1
pymysql.install_as_MySQLdb()

3.利用Django模型设计数据库表

Django 规定,如果要使用模型,必须要创建一个 app。

创建Django APP:myApp

我们使用以下命令创建一个Django app:myApp

1
django-admin.py startapp myApp

成功后的项目文件夹目录如下:

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/20210414144728624.png)

设计数据库表

在myApp下的models.py设计表:

这里我们设计一个Student表,用来存储学生信息.

表字段

字段类型

含义

student_name

Varchar类型

学生姓名

student_sex

Varchar类型

学生性别

create_time

Datetime类型

创建日期时间

1
from django.db import modelsclass Student(models.Model):    student_name = models.CharField(max_length=64)    student_sex = models.CharField(max_length=3)    create_time = models.DateTimeField(auto_now=True)

在 settings.py 中找到INSTALLED_APPS这一项,如下:

1
'django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles',

生成数据库迁移文件

在命令行中运行:

1
python manage.py makemigrations myApp

执行成功后结果:

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/20210414151307794.png)

执行迁移文件来完成数据库表的创建

在命令行中运行:

1
python manage.py migrate myApp

执行成功后结果:

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/20210414151425160.png)

查看数据库中数据库表已经生成成功

(django默认在makemigrations会为表对象创建主键id,id = models.AutoField(primary_key=True))

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/20210414160015767.png)

4.Django创建新增和查询学生信息接口

在myApp目录下的views.py中创建两个视图函数

1
from __future__ import unicode_literalsfrom django.http import JsonResponsefrom django.core import serializersfrom django.shortcuts import renderfrom django.views.decorators.http import require_http_methodsfrom myApp.models import Student@require_http_methods(["GET"])def add_student(request):        student = Student(student_name=request.GET.get('student_name'))        response['msg'] = 'success'        response['error_num'] = 0        response['error_num'] = 1return JsonResponse(response)@require_http_methods(["GET"])def show_students(request):        students = Student.objects.filter()        response['list'] = json.loads(serializers.serialize("json", students))        response['msg'] = 'success'        response['error_num'] = 0        response['error_num'] = 1return JsonResponse(response)

5.配置路由

1.在myApp目录下,新增一个urls.py文件,用于创建此APP下的分支路由,把新增的两个视图函数添加到路由里面.

1
from django.conf.urls import url    url(r'^add_book/', views.add_book),    url(r'^show_books/', views.show_books),

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/20210414162754315.png)

2.把上面创建的myApp下的分支路由加到DjangoElementUI下的主路由中urls.py.

1
from django.contrib import adminfrom django.urls import pathfrom django.conf.urls import urlfrom django.conf.urls import include    url(r'^admin/', admin.site.urls),    url(r'^api/', include(urls)),

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/20210414163356300.png)

至此Django部分已经完成,总结下我们利用Django完成了数据库的创建,并创建了两个视图函数作为接口给前端调用.

1.安装vue-cli脚手架

在DjangoElementUI根目录下输入命令:

1
npm install -g vue-cli

2.安装好后,新建一个前端工程目录:appfront

在DjangoElementUI项目根目录下输入命令:

1
vue-init webpack appfront

3.进入appfront目录安装vue所需要的依赖

1
npm install

4.安装ElementUI

1
npm i element-ui -S

5.创建新vue页面

在src/component文件夹下新建一个名为Studengt.vue的组件,通过调用之前在Django上写好的api,实现添加学生和展示学生信息的功能.

1
<el-row display="margin-top:10px"><el-input v-model="input" placeholder="请输入学生姓名" style="display:inline-table; width: 30%; float:left"></el-input><el-button type="primary" @click="addStudent()" style="float:left; margin: 2px;">新增</el-button><el-table :data="studentList" style="width: 100%" border><el-table-column prop="id" label="编号" min-width="100"><template scope="scope"> {{ scope.row.pk }} </template><el-table-column prop="student_name" label="姓名" min-width="100"><template scope="scope"> {{ scope.row.fields.student_name }} </template><el-table-column prop="student_sex" label="性别" min-width="100"><template scope="scope"> {{ scope.row.fields.student_sex }} </template><el-table-column prop="add_time" label="添加时间" min-width="100"><template scope="scope"> {{ scope.row.fields.create_time }} </template>this.$http.get('http://127.0.0.1:8000/api/add_student?student_name=' + this.input)var res = JSON.parse(response.bodyText)if (res.error_num === 0) {this.$message.error('新增学生失败,请重试')this.$http.get('http://127.0.0.1:8000/api/show_students')var res = JSON.parse(response.bodyText)if (res.error_num === 0) {this.studentList = res['list']this.$message.error('查询学生失败')<!-- Add "scoped" attribute to limit CSS to this component only -->

6.配置路由

appfront/router文件夹下的index.js中增加页面路由.

1
import Router from 'vue-router'import HelloWorld from '@/components/HelloWorld'import Student from '@/components/Student'export default new Router({

appfront文件夹下的main.js中引入ElementUI并注册.

1
import router from './router'import '../node_modules/element-ui/lib/theme-chalk/index.css'import ElementUI from 'element-ui'Vue.config.productionTip = false

7.打包并启动前端项目

打包vue项目

1
npm run build

启动前端项目

1
npm run dev

出现下面信息则说明我们前端项目已经构建成功.

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/20210415084527242.png)

去浏览器访问页面地址:http://localhost:8080/#/student

出现如下页面说明我们的页面已经成功.

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/2021041508564340.png)

截止到目前,我们已经成功通过Django创建了一个后端服务,通过Vue.js + ElementUI 实现了前端页面的构建,但是他们运行在各自的服务器,而且前端页面还无法调用后端的接口.

接下来我们需要将两个项目真正的整合到一个成一个项目.

1.引入用于HTTP解析的vue-resource

前端vue项目调用后端需要引入vue-resource

在appfront文件下运行命令:

1
npm install 

安装完成后在main.js中引入vue-resource

1
import router from './router'import '../node_modules/element-ui/lib/theme-chalk/index.css'import ElementUI from 'element-ui'import VueResource from 'vue-resource'Vue.config.productionTip = false

2.在Django层注入header

为了让后端可以识别前端需求,我们须要在Django层注入header,用Django的第三方包django-cors-headers来解决跨域问题:

在DjangoElementUI根目录下输入命令:

1
pip install django-cors-headers

在settings.py中增加相关中间件代码

1
'django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','corsheaders.middleware.CorsMiddleware',     'django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',CORS_ORIGIN_ALLOW_ALL = True   

3.修改Django路由

这一步我们通过Django路由配置连接前后端资源.

首先我们把Django的TemplateView指向我们刚才生成的前端dist文件

在DjangoElementUI目录下的urls.py中增加代码:

1
from django.conf.urls import urlfrom django.contrib import adminfrom django.conf.urls import includefrom django.views.generic import TemplateView    url(r'^admin/', admin.site.urls),    url(r'^api/', include(urls)),    url( r'^vue/', TemplateView.as_view( template_name="index.html" ) )

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/20210415091901764.png)

接着修改静态资源文件路径也指向前端appfront 相关文件

在DjangoElementUI目录下的setting.py中增加代码:

1
'BACKEND': 'django.template.backends.django.DjangoTemplates','DIRS': [os.path.join(BASE_DIR, 'appfront/dist')],  'django.template.context_processors.debug','django.template.context_processors.request','django.contrib.auth.context_processors.auth','django.contrib.messages.context_processors.messages',    os.path.join(BASE_DIR, "appfront/dist/static")

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/20210415092345733.png)

3.重新构建前端项目

appfront目录下输入命令:

1
npm run build

重新启动Django项目

1
python manage.py runserver

输入地址:http://localhost:8000/vue/#/student

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/20210415105612903.png)

添加一条记录

![](Python 基于Web框架Django 前端框架Vue.js + elementUi 实现前后端分离项目环境搭建指南/202104151057325.png)

至此,大功告成!

此份指南在配置的过程踩过不少坑,以下是踩的印象较深的坑.

1.数据库创建的过程中务必注意大小写的问题,数据库字段和Django的Models页面,View页面和Vue中的组件页面都有关联.很容易一个大小写不注意,导致整个接口无法使用.

2.连接MySQL需要按照对应的包,同时需要在根目录的_ini_.py中引入pymysql

3.在整个环境的搭建过程中VUE环境的搭建需要耗费较长的npm安装时间,需要耐心等待.

4.前后台连接需要在前端引入vue-resource,Django需要引入django-cors-headers


TestLink是最广泛使用的基于Web的开源测试管理工具。它一起同步需求和测试用例。用户可以使用这个工具创建测试项目和文档测试用例。通过TestLink,您可以为多个用户创建一个帐户,并分配不同的用户角色。管理员用户可以管理测试用例分配任务。

它支持测试用例的自动和手动执行。测试人员可以用这个工具在很短的时间内生成测试计划和测试报告。它支持各种格式的测试报告,如Excel、MS Word和HTML格式。除此之外,它还支持与许多流行的缺陷跟踪系统集成,如JIRA、MANTIS、BugZILLA、TRAC等。因为它是一种基于Web的工具,多个用户以他们的凭据和分配的角色可以同时访问其功能。在本教程中,我们将学习:

  • TestLink的优点
  • 登录到TestLink
  • 创建测试项目
  • 创建测试计划
  • 创建构建
  • 创建测试集
  • 创建测试用例
  • 将测试用例分配给测试计划
  • 在TestLink中创建用户和分配角色
  • 执行测试用例
  • 生成测试报告
  • 导出测试用例/测试集
  • 导入测试用例/测试集

TestLink的优点

  • 它支持多个项目
  • 易于导出导入测试用例
  • 易于与多种缺陷管理工具集成
  • 基于XML- RPC的自动化测试用例执行
  • 易于使用版本、关键字和测试用例ID过滤测试用例
  • 易于向多个用户分配测试用例
  • 易于生成各种格式的测试计划和测试报告
  • 向多个用户提供凭据并向其分配角色

第1步:打开TestLink主页。

  1. 输入用户名 admin;
  2. 输入密码;
  3. 点击“登录”按钮。
    这里写图片描述

创建测试项目

第1步:在主窗口中点击“测试项目管理”,它将打开另一个窗口。
这里写图片描述
第2步:点击“创建”按钮创建一个新项目。
这里写图片描述
第3步:在窗口中输入所有必需的字段,如测试项目的类别、项目名称、前缀、描述等。在填写所有必要的详细信息后,点击窗口末尾的“创建”按钮。
这里写图片描述
已成功创建项目“GURU99”:
这里写图片描述

创建测试计划

测试计划包含完整的信息,如软件测试的范围、里程碑、测试集和测试用例。一旦创建了测试项目,下一步就是创建测试计划。

第1步:从主页上点击Test Plan Management。
这里写图片描述

第2步:它将打开另一个页面,在页面底部点击“创建”按钮。
这里写图片描述

第3步:在打开的窗口中填写所有必要的信息,如名称、说明、从现有的测试计划创建等,并点击“创建”。
这里写图片描述

第4步:成功创建Gru 99测试计划。
这里写图片描述

创建构建

Build是一个特定的软件版本。

第1步:从主页的测试计划下点击“构建/发布”。
这里写图片描述

第2步:在下一个窗口中,填写软件发布的所有必要细节,然后单击“创建”以保存发布。

  1. 输入标题名;
  2. 输入关于软件发布的描述;
  3. 为状态激活标记复选框;
  4. 标记复选框状态打开;
  5. 选择发布日期;
  6. 点击“创建”按钮。
    这里写图片描述

一旦你有了一个软件发布,它会这样显示:
这里写图片描述

创建测试集

测试集是测试或验证同一组件的测试用例的集合。下面的步骤将说明如何为项目创建测试集。

第1步:点击主页上的“编辑测试用例”(即Test Specification)选项。
这里写图片描述

第2步:在面板右侧,点击设置图标这里写图片描述,它将显示一系列的测试操作。

第3步:单击测试集的“创建”按钮。
这里写图片描述

第4步:填写测试套件的所有细节,点击“保存”选项卡。

  1. 输入测试集名称;
  2. 输入测试集的详细信息;
  3. 点击“保存”按钮保存测试集的详细信息。
    这里写图片描述
    您可以看到Guru 99的测试集已被创建:
    这里写图片描述
    您的测试集出现在面板左侧,在文件夹结构树下面。

创建测试用例

测试用例保存一系列测试步骤以及预期的结果去测试特定场景。下面的步骤将解释如何创建测试用例以及测试步骤。

第1步:单击面板左侧文件夹树结构下的测试集文件夹。
这里写图片描述

第2步:点击右侧面板中的设置图标,测试用例操作列表将显示在右侧面板上。
这里写图片描述

第3步:点击测试用例操作项中的创建按钮,将会打开新窗口创建测试用例。
这里写图片描述

第4步:在测试用例页中输入详细信息。
这里写图片描述

第5步:输入详细信息后,点击“创建”按钮来保存,GURU99的测试用例就创建成功了。
这里写图片描述

第6步:点击如上所示的文件夹中的测试用例,它将打开一个窗口,再点击“创建步骤”按钮,它将打开一个测试用例步骤编辑器。
这里写图片描述

第7步:它将在同一页上打开另一个窗口,在那个窗口中,你必须输入以下细节:
1. 输入测试用例的步骤操作;
2. 输入步骤动作的预期结果;
3. 单击“保存”并添加另一步操作,或单击“保存”和“退出”,如果没有更多的步骤要添加。
这里写图片描述

第8步:一旦保存并退出测试步骤,就会像这样:
这里写图片描述

将测试用例分配给测试计划

对于测试用例要执行,它应该被分配给测试计划。这里我们将看到如何将测试用例分配给测试计划。

第1步:点击测试面板上的设置图标这里写图片描述,将会展示操作列表。

第2步:点击“添加到测试计划”。
这里写图片描述

第3步:新窗口将打开,找到你的项目“GURU99”。
1. 在测试计划上标记复选框;
2. 点击“添加”按钮。
这里写图片描述
这将将您的测试用例添加到测试计划中了。

在TestLink中创建用户和分配角色

TestLink提供用户管理和授权功能,以下是TestLink中默认角色及其权限的列表:

角色

测试用例

测试计划度量

游客

查看

查看

测试执行人员

执行

查看

测试分析人员

编辑&执行

查看

负责人&管理员

编辑&执行

编辑&执行

第1步:从TestLink主页,点击导航栏中的用户/角色图标。
这里写图片描述

第2步:点击创建。
这里写图片描述

第3步:填写所有用户详细信息并点击“保存”按钮。
这里写图片描述

在列表中,我们可以看到用户已经被创建了:
这里写图片描述

第4步:将测试项目角色分配给用户。
1. 单击“分配测试项目角色”选项卡;
2. 选择项目名称;
3. 从下拉菜单中选择用户角色。
这里写图片描述

执行测试用例

在TestLink中,我们可以运行一个测试用例,并改变一个测试用例的执行状态。测试用例的状态可以设置为“阻塞”“通过”或“失败”。最初,它将处于“不运行”状态,但是一旦您更新它,它就不能再次更改为“不运行”状态。

第1步:从导航栏点击“测试执行”链接,它将引导您进入测试执行面板。
这里写图片描述

第2步:从左侧面板选择要运行的测试用例。
这里写图片描述

第3步:一旦选择了测试用例,它将打开一个窗口。
这里写图片描述

第4步:遵循以下步骤:

  1. 输入与被执行的测试用例相关的注释;
  2. 选择其状态。
    这里写图片描述

第5步:在同一页上,您可以填写关于测试用例执行的类似细节,填上详细信息,然后在右下角选择状态保存。
这里写图片描述

生成测试报告

TestLink支持各种测试报告格式:

  • HTML
  • MS word
  • MS Excel
  • OpenOffice Writer
  • OpenOffice Calc

第1步:从导航栏中点击测试报告选项。
这里写图片描述

第2步:从左侧面板选择“测试报告”链接。
这里写图片描述

第3步:按照以下步骤生成报告:

  1. 标记您想在测试报告中显示的选项;
  2. 点击项目文件夹。

测试报告看起来像这样:
这里写图片描述

导出测试用例/测试集

TestLink提供了导出测试项目/测试集的功能,然后您可以将它们导入到不同服务器或系统的另一个TestLink项目中。为了做到这一点,你应遵循以下步骤。

第1步:在编辑测试用例页面中选择你想要导出的测试用例。
这里写图片描述

第2步:点击面板右侧的设置图标这里写图片描述,它将显示可以在测试用例上执行的所有操作。

第3步:点击“导出”按钮。
这里写图片描述

第4步:它将打开另一个窗口,按需要标记选项并单击“导出”按钮。
这里写图片描述
生成如下XML:
这里写图片描述

导入测试用例/测试集

第1步:选择要导入测试用例的测试集文件夹。
这里写图片描述

第2步:点击面板右侧的设置图标这里写图片描述,它将显示可以在测试集/测试用例上执行的所有操作。

第3步:点击测试用例操作列表中的导入按钮。
这里写图片描述

第4步:浏览选择从TestLink导出的XML测试用例文件并点击上传按钮。

  1. 使用浏览选项来选择您从TestLink导出的XML测试用例文件;
  2. 点击“上传文件”。
    这里写图片描述
    当您上传文件时,它将打开声明导入测试用例的窗口。
    这里写图片描述

第5步:测试用例将会被上传并显示在你选择的测试集里。
这里写图片描述

总结:
在本教程中,我们已经介绍了TestLink的各个方面,比如如何使用TestLink进行测试管理。它将一步一步地说明如何管理项目的测试计划、如何创建用户并相应地分配它们的角色,甚至如何将测试用例导入或导出到项目中。其他有用的功能,如生成报告等也在本教程中得到了很好的演示。


可以在一个Jenkins的全局系统配置中设置多个SonarQube服务器。
在每个具体的任务中,可以指定特定的SonarQube服务器来完成代码扫描。

默认已安装并启动Jenkins与SonarQube。

2.1 安装SonarQube Scanner插件

2.2 配置 SonarQube Server 信息

Jenkins—》系统管理—-》系统设置,配置 SonarQube Server 信息

在SonarQube上生成令牌

将令牌添加到Jenkins

选择应用令牌

2.3 配置 SonarQube Scanner

Jenkins—》系统管理—》全局工具配置, 配置 SonarQube Scanner

2.4 Jenkins任务配置

设置源码仓库

指定构建前的操作

1
2
sonar.projectKey=testsonar
sonar.sources=.
  • Path to project properties:指定sonar-project.properties 文件,默认使用项目根目录的sonar-project.properties文件
  • Analysis properties:传递给 SonarQube的配置参数,优先级高于 sonar-project.properties 文件的参数
  • Additional arguments:附加的参数,例如-X表示启用Debug 模式输出更多的日志信息

指定构建参数

1
clean package sonar:sonar -Dsonar.host.url=http:

3.1 查看扫描报告

控制台输出

在任务界面会出现多个Sonar的链接

点击Sonar链接 即可看到扫描报告

3.2 直接在SonarQube Server上查看

需要借助JaCoCo插件,才能获取到代码的真实单元测试覆盖率,否则在有单元测试的情况下也只会显示为0%。
单击“覆盖率”可看到详细的代码统计展示。

安装JaCoCo插件

通过指定构建的Goals and options参数
clean package org.jacoco:jacoco-maven-plugin:prepare-agent sonar:sonar -Dsonar.host.url=http://192.168.16.200:9000

注意:添加如下参数-Dmaven.test.failure.ignore=false可以忽略失败的单元测试,以便完成对覆盖率的统计。

在SonarQube社区版本中,可以通过配置构建的Goals and options参数,来简单地进行不同分支的扫描。
只需要增加参数-Dsonar.branch=<branch name>
针对同一项目的不同分支进行构建后,在Sonar界面,会看到根据“ ”的扫描任务和状态。

这篇文章延续上一篇 《win10下docker-compose搭建gitlab+gerrit+sonar+jenkins持续集成环境》,上一篇我们搭建好了持续集成的环境,这篇文章介绍如何将这些工具结合起来,把每个环节打通。下一篇我们会使用集成环境做安卓开发实战。

idea和Android SDK的下载安装使用不是本文的重点,我假设各位都是成熟的安卓开发人员并且已经搭建好了基于idea的安卓开发环境(菜鸟一般不需要了解敏捷开发)。

我们回过头来看一下这张集成图 ,这里面没有把sonarqube画出来,因为sonarqube是可以和Jenkins进行集成的,这在后面我们会慢慢提到。
在这里插入图片描述

使用浏览器打开gitlab网址,我这里是localhost:10080,首次打开需要修改密码。修改成功后我们就可以登录了,这个时候用的管理员账号。
在这里插入图片描述

注册开发机账号

Step1:gitlab配置
我们还需要gitlab上注册一个普通账号,叫develop01,具体如下,点击注册他会自动登录,这个developer01就像我们普通的开发者,再window下做开发,因此我需要为这位开发者配置对应的ssh信息。
由于windows下已经安装了git,因此直接打开C:\Users\Administrator\.ssh,复制出里面的内容,粘贴到gitlab该用户设置的ssh配置上(由于我本地机器配置的qq邮箱只好用自己的qq邮箱)
在这里插入图片描述然后点击增加密钥,就配置好了;
在这里插入图片描述Step2:开发机配置
如果你的开发机没有配置多个git账户可以略过这一步;如果你的开发机git配置了多个用户,需要先把生成的ssh添加进来,否则会出现如下错误:

1
2
3
4
5
6
7
8
9
10
11
12
$ git clone ssh://git@localhost:10022/dev-group/ci-test-project.git
Cloning into 'ci-test-project'...
The authenticity of host '[localhost]:10022 ([::1]:10022)' can't be established.
ECDSA key fingerprint is SHA256:XMNZCD1uHPib/WU/4OziotP557y/jefwmhoVCmjkKK8.
Are you sure you want to continue connecting (yes/no/[fingerprint])? n
Please type 'yes', 'no' or the fingerprint:
Host key verification failed.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

解决方法是:

1
2
$ ssh-agent bash
ssh-add ~/.ssh/id_rsa

创建gitlab项目

我们假定管理员账号是技术总监,那么技术总监需要创建一个软件项目。
登陆进去我们进入到主页面,点击创建项目->私有项目->填写项目信息->完成。这个时候跳转到创建成功页面,并提示我们需要配置ssh key。
在这里插入图片描述
由于我们的代码首先需要通过gerrit审核才能合并到gitlab,因此,我们需要添加一个gerrit的用户。原理很简单,就是使用gerrit服务器生成一个gerrit的sshkey,配置到gitlab上,这样gerrit所在的服务器等同于gitlab的客户机,就可以通过gerrit服务器向gitlab推送代码了。

要拿到docker中gerrit容器的ssh信息,需要进入该容器,使用docker exec -it xxx /bin/bash或者直接在docker的gerrit容器上点击cli按钮。进入控制台;
在这里插入图片描述
Step1:确认gerrit容器是否已经配置了git

1
2

fatal: unable to read config file '/root/.gitconfig': No such file or directory

发现没有配置,我们来配置一下。
我们知道配置git需要两个信息:username和email,因此我们需要登录gitlab的管理员账号查看对应的邮箱。为了方便区别我把邮箱修改成了gerrit@example.com;
在这里插入图片描述Step2: 我们回到gerrit容器中,使用ssh-keygen命令生成ssh信息(三次回车),然后使用cat命令打印ssh信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
sh-4.2$ ssh-keygen -t rsa -C gerrit@example.com
Generating public/private rsa key pair.
Enter file in which to save the key (/var/gerrit/.ssh/id_rsa):
Created directory '/var/gerrit/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /var/gerrit/.ssh/id_rsa.
Your public key has been saved in /var/gerrit/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:yhrSuWAlFyK2IC0NOwIjczbLSceobmUSZpW8IJlsH24 gerrit@example.com
The key's randomart image is:
+---[RSA 2048]----+
|BoB+o |
|*^.O. |
|&o% + |
|*=.E . |
|..* o S |
| o = o . |
|. + + o |
| . o + |
| o |
+----[SHA256]-----+
sh-4.2$ cat /var/gerrit/.ssh/id_rsa.pub
ssh-rsa ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDs/u6ZEU0ES1niaGpD7PbDnQMkDpjf0YW0XR9sYgHbawL+F4OBjc3wJ2xHjOLQNZHPpt/yIuSYWphGpSJmrWZ6YwiKQEV0BJIf2ttNn5qSz9ds9riE6eCCn2hJu/mIh2f1+DK3xF7lryzUAYhO8c0Mb1WAxD3xp69A+jKGvMvx6/AaZvjIm4fiQv/0JZ05nX9p6oqyYVO9XE25i5eJ9erJrLVeUx8wgxpfWROcH27Yt1YOMcj50m5pGbjp997tUO+r+jUEdhcpilW8GPyvV9eW+69xEbRKeCsDmBPKr3G5Gjn/iVeZSeH7tj/YJOU5Y281yJd6XL21uvHSh+o8zvv9 gerrit@example.com

然后和前面一样,在gitlab端配置管理员账户的ssh信息(为了方便辨识,我把原本为root的用户名改成了gerrit),用户信息也更新成了gerrit@example.com
在这里插入图片描述Step3:创建开发组
接下来就是创建一个开发组。
在这里插入图片描述
Step4:创建组内项目
创建好开发组之后会跳出一个页面,我们继续点击新建项目,项目名称就叫ci-test-project吧。
在这里插入图片描述Step5 :把developer01拉入小组
点击群组->dev-group->成员->搜索成员并添加为报告者(repoter)->添加到群组;
在这里插入图片描述Step6:测试创建的项目
由于我们刚刚在添加开发机的时候角色赋予的是repoter,它是没有提交权限的,我们来验证一下;

1
2
3
4
5
6
7
8
9
10
11
$ git clone ssh://git@localhost:10022/dev-group/ci-test-project.git
$ cd ci-test-project/
$ touch testfile.txt
$ git add testfile.txt
$ git commit -m 'add testfile'
$ git push

GitLab: You are not allowed to push code to this project.
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.

嗯,被拒绝了,成功了。因为普通用户没有直接push的权限。需要先review到gerrit上进行审核并commit后,才能更新到代码中心仓库里。

  1. 页面上写的是git clone git@localhost:dev-group/ci-test-project.git
    但是我这里使用docker做了端口映射,因此需要写出上面这种形式
  2. 如果你在clone的时候发现执行不了,试试在C:/docker/gitlab/etc/gitlab.rb文件开头加上:
    gitlab_rails['gitlab_shell_ssh_port'] = 10022

我们通过在本地创建一个文件,使用push指令测试该用户是否正常,如果push被拒绝说明配置正常。

问题1:一直卡在git clone。control+c之后提示没有权限访问这个项目。这是一个笼统的回答,要看真正问题出现在哪里,需要看日志,那么日志就放在安装目录的log文件夹下面:“C:\Docker\gitlab\log\sshd”。
打开current文件,在最下面我们会看到错误日志,我这里是权限开得太大了;

1
2
3
4
5
6
7
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2020-03-12_02:47:17.13033 Permissions 0755 for '/etc/gitlab/ssh_host_ed25519_key' are too open.
2020-03-12_02:47:17.13100 It is required that your private key files are NOT accessible by others.
2020-03-12_02:47:17.13210 This private key will be ignored.
2020-03-12_02:47:17.13268 key_load_private: bad permissions
2020-03-12_02:47:17.13334 Could not load host key: /etc/gitlab/ssh_host_ed25519_key
2020-03-12_02:47:17.13429 Bad protocol version identification 'HEAD / HTTP/1.1' from 172.18.0.1 port 45886

知道原因就很简单了,我们找到/etc/gitlab/ssh_host_ed25519_key然后把他的权限修改成0771就可以了。如果修改之后权限没有变化就可能是你的key保存在了windows机器上,我的办法就是重新安装了gitlab然后把key保存在了容器里面。(其实windows下我们只需要留一个宿主机和容器通讯的文件夹就可以了,因为权限问题很肉疼的)。

我们知道Gerrit有好几种认证方式,常见的OAuth(Gitlab的OAuth和Github的OAuth),Http,Ldap,openID。我们这里使用的是Ldap方式(安装gerrit镜像的时候同时自动安装了),Ldap在管理用户信息上还是蛮好用的。

Step1:使用ldap创建一个Gerrit账号(上一篇文章有介绍,这里不再赘述);注意邮箱要和gitlab的管理员邮箱保持一致。

参数为:
Given Name: Gerrit
Last Name: Admin
Common Name: Gerrit Admin
User ID: gerrit
Email: gerrit@example.com
Password: 12345678

Step2:使用该账号登录Gerrit,网址是http://localhost:20080/
Step3:登陆后点击右上角用户->Setting->SSH Keys配置sshkey,值为Gitlab上配置的管理员(Gerrit)的SSH;
在这里插入图片描述Step4:采用同样方法为开发人员develop01在gerrit上注册账号,并配置对应的ssh key(开发机上的ssh key,与gitlab用户对应);

在这里插入图片描述
Step5:以同样的方式为jenkins创建账号,参数为:

Given Name: Jenkins
Last Name: Admin
Common Name: Jenkins Admin
User ID: jenkins
Email: jenkins@example.com
Password: 12345678

到这个时候,ldap上有三个账号可以登录gerrit了:
在这里插入图片描述Step6:进入Jenkins所在的服务器,生成jenkins的ssh并设置到gerrit对应账户

1
2
3
4
5
$ ssh-keygen -t rsa -C jenkins@example.com
Generating public/private rsa key pair.
...
$ cat /var/jenkins_home/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNK8+nl9XptdAedHl3r4zuvmdzUhMjySuHhTMi7kI/wkq8uiX+xNfP9vsCuo/xio4icr9BC6nJFMUNlI8amhH+ub9RJmsQPdHjPT5rAiYxmLjhKng8WY2pznnvhsqflN+DBnPvuekDvnynkt7gngHkf4b/SowWlVzVn4S3msrJ5zxcy0vU1oPG8xoDA4kQc4HfgxApzeZsePe2JPcwcXlDmvgtPHul1xiXCwkpmsM7Vd/xQSY7O4cZdt25qfuL7HprovCdhVEJuScd4AENOLK6NUiHwkkCGA0vkB+mpi/2Zq41jXvfH2v+6gipAPDZjt+a3aUJ7mUisCiYtl7dZO+9 jenkins@example.com

注意:这里一定要写密码,我的密码是11111111(8个1)

Step7:将Jenkins添加到Non-Interactive Users 用户组
使用管理员账号登陆gerrit->BROWSE->Groups > Non-Interactive Users > members->Add your jenkins user。

Step8:手动添加Verified标签功能(已经有了就跳过这一步)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

sh-4.2$ git init cfg; cd cfg
sh-4.2$ git config --global user.name 'gerrit'
sh-4.2$ git config --global user.email 'gerrit@example.com'
sh-4.2$ git remote add origin ssh://gerrit@localhost:29418/All-Projects
sh-4.2$ git pull origin refs/meta/config
sh-4.2$ vi project.config
[label "Verified"]
function = MaxWithBlock
value = -1 Fails
value = 0 No score
value = +1 Verified
sh-4.2$ git commit -a -m 'Updated permissions'
sh-4.2$ git push origin HEAD:refs/meta/config
sh-4.2$ rm -rf cfg
sh-4.2$ rm -rf cfg

以上方法也可以在本地使用push的方式完成修改。然后就可以看到这个标签了;
在这里插入图片描述

Step9:配置All-Projects权限
Browe->Repositories->All-Projects->Access-> Edit,往下拉,找到Reference: refs/*在下面有一个输入框,在输入框输入non会出现Non-Interactive Users点击add,就给这个用户组添加了该特性权限。
然后以同样的方法在Reference: refs/heads/*下面的Label Code-Review把Non-Interactive Users加上去,值为-1, +1 ;
同样的Label Verified也添加Non-Interactive Users设置为-1, +1 ;

因为我的gerrit版本是3.0,在2.7+的版本上还需要额外配置Stream Events的权限,位于Global Capabilities的节点下,点击保存,完毕;
在这里插入图片描述

Step1:安装插件
使用管理员账户登录jenkins后,点击我们需要安装Gerrit Trigger插件和Git plugin插件;
“系统管理”->拖到下面“插件管理”->”可选插件”->Filter搜索->输入Gerrit Trigger安装,然后输入Git plugin,也安装。勾选安装完成后重启。jenkins会自动重启,我们等待他重启完成。

重启完成我们登录之后,我们可以在插件管理中看到Gerrit Jenkins:
在这里插入图片描述Step2:配置Gerrit Trigger
点击插件->点击左侧的”New Server”->在”Add New Server”一栏输入名字,我这里是”check4Gerrit”->勾选”Gerrit Server with Default Configurations”->点击”OK”;

然后进行”Gerrit Connection Setting”,
在这里插入图片描述我们看到顶上有一排黄色的警告,意思就是没有安装event-log,我参考这篇文章搞了一个,把这个jar放在gerrit的plugins文件夹里面。如上所示,信息填写完毕之后,点击右侧的test Connection,提示success表示配置成功;

我这里的信息是:

Name:check4Gerrit
Hostname:192.168.31.189
Frontend URL:http://192.168.31.189:20080
SSH Port:29418
Username:jenkins
E-mail:jenkins@example.com
SSH Keyfile:/var/jenkins_home/.ssh/id_rsa
SSH Keyfile Password:11111111

在这一步我卡了很久,一直没成功,最后是把给ssh设置了密码,并且把ip地址改成了宿主机的局域网ip,然后才看到期盼已久的success。最终这里会变成蓝色;
在这里插入图片描述

添加review命令

虽然我们配置dev01客户机没有push权限,但是我们会让他有git review的权限,不过这里我们需要配置一下才可以。我们需要在项目里面添加一个 .gitreview来支持git review。目前只有管理员组才具备提交权限,也就是gerrit账号。因此我们需要用gerrit账号把代码下过来并添加.gitreview文件。

以root方式进入gerrit所在的容器;不加–user root进入的非root账号。由于我之前创建的sshkey在非root用户的.ssh目录下,因此我只是用root用户创建了一个开发权限的文件夹就退出切换成了非root用户;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
docker exec -it --user root gerrit /bin/bash 
[root@fba3f1d5f6f6 /]
[root@fba3f1d5f6f6 opt]
[root@fba3f1d5f6f6 opt]
[root@fba3f1d5f6f6 /]
PS C:\Docker\gerrit> docker exec -it gerrit /bin/bash
bash-4.2$ cd opt/testCode/
bash-4.2$ git clone ssh://git@192.168.31.189:10022/dev-group/ci-test-project.git
Cloning into 'ci-test-project'...
The authenticity of host '[192.168.31.189]:10022 ([192.168.31.189]:10022)' can't be established.
ECDSA key fingerprint is SHA256:B/IihaaLfGY0ZW7CtBhfCFvp9Nh2lZtMNAB51gjQWb0.
ECDSA key fingerprint is MD5:ec:8d:ae:bc:f3:5a:6a:36:c3:18:3d:75:46:97:e0:90.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[192.168.31.189]:10022' (ECDSA) to the list of known hosts.
remote: Counting objects: 3, done

然后我们添加.gitreview,.gitreview的内容如下(192.168.31.189是宿主机的ip):

1
2
3
4
[gerrit]
host=192.168.31.189
port=29418
project=ci-test-project.git
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
bash-4.2$ cd ci-test-project/
bash-4.2$ vi .gitreview
bash-4.2$ git add .gitreview
bash-4.2$ git config --global user.name 'gerrit'
bash-4.2$ git config --global user.email 'gerrit@example.com'
bash-4.2$ git commit .gitreview -m 'add .gitreview file by gerrit.'
[master 9b7dc37] add .gitreview file by gerrit.
1 file changed, 4 insertions(+)
create mode 100644 .gitreview
bash-4.2$ git push origin master
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 343 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To ssh://git@192.168.31.189:10022/dev-group/ci-test-project.git
4ef534d..9b7dc37 master -> master

以同样的方法添加.testr.conf 文件(由于下面的Python 代码我使用了 testr,需要先在Jenkins容器内安装 testr 命令yum -y install epel-release->yum -y install python-pip->pip install testrepository,否则会编译不过),.testr.conf 文件内容如下:

1
2
3
4
5
6
7
[DEFAULT]
test_command=OS_STDOUT_CAPTURE=1
OS_STDERR_CAPTURE=1
OS_TEST_TIMEOUT=60
${PYTHON:-python} -m subunit.run discover -t ./ ./ $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=-list

然后我们把它提交到版本仓库;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
bash-4.2$ vi .testr.conf
bash-4.2$ git add .testr.conf
bash-4.2$ git commit .testr.conf -m 'add .testr.conf file by gerrit'
[master 54a8810] add .testr.conf file by gerrit
1 file changed, 7 insertions(+)
create mode 100644 .testr.conf
bash-4.2$ git push origin master
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 480 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To ssh://git@192.168.31.189:10022/dev-group/ci-test-project.git
9b7dc37..54a8810 master -> master

这个时候我们回到gitlab就能看到我们提交的这两个文件了。
在这里插入图片描述

同步gerrit和Gitlab项目文件

到目前为止,gerrit上面并没有和gitlab同步的项目,我们需要把gerrit和gitlab关联起来,也就是说必须在gerrit上创建相同的项目,并有相同的仓库文件;

有两种方式创建项目,一种是登录gerrit的管理页面在Repo点击create new,还有一种是在gerrit容器中使用命令ssh-gerrit gerrit create-project ci-test-project (后一种方式可以创建空的项目);

接下来我们要使用gerrit上的管理员账户clone –bare Gitlab上的仓库到 Gerrit ,由于我gerrit的管理员和gitlab的管理员都是gerrit且有相同的ssh key,因此我不需要担心两个弄混导致的同步问题;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
sh-4.2$ cd /var/gerrit/git/
sh-4.2$ ls
All-Projects.git All-Users.git ci-test-project.git
sh-4.2$ rm -rf ci-test-project.git/
sh-4.2$ git clone --bare ssh://git@192.168.31.189:10022/dev-group/ci-test-project.git
Cloning into bare repository 'ci-test-project.git'...
remote: Counting objects: 12, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 12 (delta 1), reused 0 (delta 0)
Receiving objects: 100% (12/12), done.
Resolving deltas: 100% (1/1), done.
sh-4.2$ cd ci-test-project.git/
sh-4.2$ ls
HEAD branches config description hooks info objects packed-refs refs

这个时候gerrit的ci项目下的文件就和gitlab一毛一样的了。

gerrit和Gitlab项目联动

现在只是在gerrit上复制了gitlab的文件,还没有实现真正的联动。我们还不能把gerrit上审核的代码提交到gitlab。我们要的效果是gerrit上的ci上的仓库已发生变化就立马同步到gitlab上去。这个时候就需要使用插件做触发器啦,这个插件叫做Replication ,gerrit默认自带了这个插件,因此我们需要配置这个插件。

修改 /var/gerrit/etc/replication.config,如果修改的是C:\Docker\gerrit\etc\replication.config。确认一下replication.config文件访问权限为600,否则后面会报错。

1
2
3
4
5
6
7
[remote "ci-test-project"]
projects = ci-test-project
url = ssh://git@192.168.31.189:10022/dev-group/ci-test-project.git
push = +refs/heads/*:refs/heads/*
push = +refs/tags/*:refs/tags/*
push = +refs/changes/*:refs/changes/*
threads = 3

然后设置gerrit用户的 ~/.ssh/config

1
2
3
Host 192.168.31.189:
IdentityFile ~/.ssh/id_rsa
PreferredAuthentications publickey

在known_hosts中给192.168.31.189添加rsa密钥(如果你的端口号不是22就需要把-p 端口号加上,我这里是10022,所以需要加上);

1
2
3
sh-4.2$ vi ~/.ssh/known_hosts
sh-4.2$ sh -c "ssh-keyscan -p 10022 -t rsa 192.168.31.189 >> /var/gerrit/.ssh/known_hosts"
sh-4.2$ sh -c "ssh-keygen -H -f ~/.ssh/known_hosts"

到这里,项目复制就完成了,如果需要复制多个项目,则在 replication.config 中添加多个 [remote ….] 字段即可。

安装必要插件

登陆jenkins,“系统管理”->“管理插件”->“可选插件”->选择Git Pluin插件进行安装。(我的可选中心在安装中文插件后一直菊花疼,最终我从插件中心手动下载了一个安装)。
安装Git插件是为了创建项目的时候能够支持git触发,否则是没办法做联动的。Git插件长这样,别下错了。
在这里插入图片描述

创建项目

Git插件安装成功后,我们在jenkins上添加一个和gitlab同名的项目。jenkins->新建任务->填入名字ci-test-project,勾选构建自由风格->确定到下一页->源码管理选择Git->填入如下字段:

源码管理:Git
Repository URL:http://192.168.31.189:20080/ci-test-project(和gerrit仓库http地址对应)
Branches to build:origin/$GERRIT_BRANCH
构建触发器:Gerrit event

在这里插入图片描述在这里插入图片描述在这里插入图片描述
这个时候我们配置好了,在主界面上会看到这个任务。
在这里插入图片描述接下来就是做联调测试了。

测试流程如下:
我们在开发机上使用developer01账号增加一个文件,并将文件提交到gerrit的HEAD:refs/for/master分支上。

1
2
3
4
5
6
$ git clone "ssh://developer01@localhost:29418/ci-test-project" && scp -p -P 29418 developer01@localhost:hooks/commit-msg "ci-test-project/.git/hooks/"
$ cd ci-test-project/
$ touch test.txt
$ git add test.txt
$ git commit -m 'test'
$ git push origin HEAD:refs/for/master

然后我们会在gerrit上看到这条记录,
在这里插入图片描述我们会看到jenkins已经verfiled而且是+1,其实是因为代码一提交就会触发jenkins使用构建脚本构建这个代码,构建成功就会+1。于是我点击了codereview+2;在这里插入图片描述
然后说明可以提交了,于是乎我点击submit。状态变成了merged。而且我们能在merged一栏可以看到:
在这里插入图片描述进到Gitlab项目查看,发现代码已经同步过来了。(最开始由于在做gerrit和Gitlab项目联动的时候没有添加端口号导致折腾了半天没有通,看gerrit的repulic日志才发现这个问题)。
在这里插入图片描述然后我们在Jenkins中也会看到编译成功了。蓝色表示成功,红色表示失败。天气图标表示多云,意思是又存在不成功的,但是总体ok(Jenkins还真是人性化);
在这里插入图片描述

安卓开发环境

windows的android sdk和Linux下的还是有一定区别的,因此建议在windows和linux下下载相同的sdk环境。为了确保版本一致,我都下载了r23的,linux的sdk下载戳这里。linux安装sdk使用如下命令:

1
2
android list sdk --all
android update sdk -u -a -t 序号

window的sdk配置比较简单,麻烦的是linux,因为要解决被墙的问题,这里我提供一种代理的方式,比如我们使用list sdk ,在中间–proxy一下。

1
./android list sdk --proxy-host mirrors.neusoft.edu.cn --proxy-port 80 -s --all

然后再Android studio中创建了一个工程,把这个工程的内容移到了之前使用developer01账号从gerrit克隆下来的项目ci-test-project中。再次使用android Studio打开,运行,安装到手机,确定项目代码是可以编译成功的。
在这里插入图片描述

Jenkins配Android SDK

点击Jenkins的系统管理->系统配置->找到全局属性->勾选环境变量->按如下方式添加ANDROID_HOME后保存。
在这里插入图片描述

配置gradle

首先要安装gradle插件,如果你已经安装好了,可以跳过这一步。Gradle的插件名字就叫做Gradle,大家注意辨别,这里就不然贴图介绍怎么安装了(gradle安装经常失败我最终不得不使用离线安装一个个把依赖安装上了)。

点击系统管理->全局工具配置->配置Git;JDK;Gradle,最后保存;由于Jenkins自带jdk1.8所以我这里不需要配置。在Jenkins容器中使用java -version知道是否已经安装了java;Git也不需要配置。

1
2
3
4
5
6
7
$ java -version
openjdk version "1.8.0_242"
OpenJDK Runtime Environment (build 1.8.0_242-b08)
OpenJDK 64-Bit Server VM (build 25.242-b08, mixed mode)

$ git --version
git version 2.11.0

那么我们配置一下gradle,我们在gradle一栏新增安装,需要注意的是gradle的版本需要和android 项目代码的gradle保持一致。我项目代码中gradle版本为4.10.1,因此安装的时候也需要选择对应版本。

1
2
3
4
5
6

distributionBase=GRADLE_USER_HOME
distributionUrl=https\:
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

在这里插入图片描述

Tasks:--stacktrace build
Root Build script:${WORKSPACE}
Build File:${WORKSPACE}\build.gradle

创建Apk构建任务

由于我们在前面已经构建了一个ci-test-project,因此这里我们只需要在那个构建上修改一下,添加gradle构建。
找到添加构建步骤 选择 Invoke Gradle script,选择gradle版本->保存。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200313144720523.png?x-oss-process=image/watermark,type\_ZmFuZ3poZW5naGVpdGk,shadow\_10,text\_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3pob25nbHVuc2h1bg==,size\_16,color\_FFFFFF,t\_70

提交代码,通过审核触发构建

前面我们虽然把代码写好了,带式还没有提交上去,这个时候我们来提交一下。
在这里插入图片描述我们点进来发现Jenkins已经verfied+1了。转到Jenkins发现已经构建成功。
在这里插入图片描述我们在gerrit上把这个提交merged(注意要等待verfied+1也就是jenkins构建成功才能submit),我公共构建了一个错误,我们发现是不能够submit的。
在这里插入图片描述

获取编译结果

然后我们需要设置用于存档的结果文件,我们这里是一个apk文件,需要修改构建配置如下 (对应你android studio编译后的apk输出目录).我这里是myapplication/build/outputs/*.apk
${WORKSPACE}\app\build\outputs\apk\app-debug.apk


赠人玫瑰手留余香,帮忙点个赞吧。

目录


1. 持续集成介绍

1.1 概念

1.2 持续集成的好处

2. GitLab持续集成(CI)

2.1 简介

2.2 GitLab简单原理图

2.3 GitLab持续集成所需环境

2.4 需要了解知识

3. 搭建GitLab持续集成环境(NET版)

3.1 环境搭建

3.1.1 基础环境搭建

3.1.2 Git安装

3.1.3 NuGet安装

3.2 相关配置

3.2.1 Git环境变量配置

3.2.2 PowerShell调用测试

3.2.3 GitLab-Runner下载

3.3 GitLab查看项目的Runners

3.4 构建GitLab-Runner服务

3.4.1 介绍

3.4.2 下载软件(没下载的请下载)

3.4.3 注册信息

3.4.4 开启gitlab-runner服务

3.4.5 修改协议config.toml文件(重要)

3.5 构建.gitlab-ci.yml脚本

3.6 完成配置

4. 常见问题解决

4.1 GitLab出现Pending卡住

4.2 GitLab CI乱码问题

4.3 明明错误,但Build成功

4.4 .gitlab-ci.yml脚本错误


1. 持续集成介绍


1.1 概念

持续集成是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

1.2 持续集成的好处

1)快速发现错误。每完成一点更新,就集成到主干,可以快速发现错误,定位错误也比较容易。

2)防止分支大幅偏离主干。如果不是经常集成,主干又在不断更新,会导致以后集成的难度变大,甚至难以集成。

2. GitLab****持续集成(CI)


2.1 简介

在GitLab 8.0+提供了持续集成的功能,在GitLab中有个Runners的概念。

Runner一共有三种类型

  1. 本地Runner

  2. 普通的服务器上的Runner

  3. 基于Docker的Runner

2.2 GitLab****简单原理图

本文只介绍GitLab对NET进行持续集成

2.3 GitLab****持续集成所需环境

开发环境:VS2015、Git

GitLab****服务器环境:GitLab 8.0+

Runner-CI****服务器:window、Git、Msbuild、Nuget、PowerShell、GitLab-Runner

2.4 需要了解知识

Git操作、GitLab、Msbuild&Nuget命令行、Powershell命令行

3. 搭建GitLab持续集成环境(NET版)


3.1 环境搭建

3.1.1 基础环境****搭建

找一台电脑(服务器最好)系统安装为window 7(x64,改成英文版最好),并且机子安装了.net framework4.0运行环境(里面要有MsBuild)

3.1.2 Git****安装

安装Git,下载地址 https://git-scm.com/download/win

3.1.3 NuGet****安装

安装NuGet.exe,下载地址:http://nuget.codeplex.com/downloads/get/669083

3.2 相关配置

3.2.1 Git****环境变量配置

计算机右键—>属性里单击选择—>环境变量

Git 目录下的 bin(如 C:\Program Files (x86)\Git\bin)添加到 PATH 环境变量。

如下图:选择 PATH编辑,将 bin 的路径(C:\Program Files (x86)\Git\bin)添加到变量值

详细配置参考方法(二选一即可)

【手动配置环境变量】

http://jingyan.baidu.com/article/fec4bce271601ff2618d8be3.html

【Git安装自动配置环境变量】

http://jingyan.baidu.com/article/9f7e7ec0b17cac6f2815548d.html

3.2.2 PowerShell****调用测试

PowerShell是调用方式(GitLab提供很多种方式),本文只针对PowerShell方式进行演示。PowerShell可以理解为就是cmd的升级版。

打开PowerShell,测试Git、MsBuild、NuGet命令行能否在PowerShell中使用(如果不想测试,请继续往下看)。

举例:

测试Git

3.2.3 GitLab-Runner****下载

首先,下载gitlab-ci-multi-runner-windows-amd64,并将其放到C:\CI

下载地址:

https://gitlab-ci-multi-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-ci-multi-runner-windows-amd64.exe

3.3 GitLab****查看项目的Runners

点击一个项目->Settings->Runners, 得到Url****地址①registration token****②

3.4 构建GitLab-Runner服务

3.4.1 介绍

基础环境已经搭建完成,如何将这台计算机真正变成一台Runner-CI服务器,我们需要详细介绍一下。

3.4.2 下载软件(没下载的请下载)

首先,下载gitlab-ci-multi-runner-windows-amd64,并将其放到 D:\CI_Test

下载地址:

https://gitlab-ci-multi-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-ci-multi-runner-windows-amd64.exe

3.4.3 注册信息

运行cmd命令(以管理员身份打开cmd)

输入命令为:

cd \

cd ci

gitlab-ci-multi-runner-windows-amd64.exe register

根据提示,填写

  1. GitLab->Runners的Url地址①

  2. GitLab->Runners的registration token②

  3. runner名称,这个随便写

  4. 分支名,master

  5. 协议方式,shell

如下图填写信息红色部分

3.4.4 开启gitlab-runner服务

输入开启命令,并检查window服务中和GitLab->Runners中是否开启成功

gitlab-ci-multi-runner-windows-amd64.exe install

gitlab-ci-multi-runner-windows-amd64.exe start

[

3.4.5 修改协议config.toml文件(重要)

注册成功后,在文件夹中找到config.toml,在[[runners]]后面添加**shell = “powershell”**节点

3.5 构建.gitlab-ci.yml脚本

【.gitlab-ci.yml内容为】

复制代码

stages: - build

job:

stage: build

script: - echo “Restoring NuGet Packages…”

  • C:\test\nuget.exe restore “ConsoleApplication1.sln”

  • echo “Solution Build…”

  • C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe /p:Configuration=Debug /p:Platform=”Any CPU” /consoleloggerparameters:ErrorsOnly /maxcpucount /nologo /property:Configuration=Release /verbosity:quiet “ConsoleApplication1.sln” tags:

except: - tags

复制代码

下图红框中的命令,只要将路径修改为”ConsoleApplication1.sln”的实际路径就能直接从Powershell中运行。注意:如果报错”ConsoleApplication1.sln”找不到可以尝试变为”src/ConsoleApplication1.sln”

3.6 完成配置

提交代码测试

成功:点击查看成功日志

失败:点击查看错误日志

编译中:点击查看编译中的日志

.gitlab-ci.yml脚本错误:,点击跳转到.gitlab-ci.yml验证页面

4. 常见问题解决


4.1 GitLab****出现Pending卡住

请检查Runner-CI服务器的GitLab-Runner服务是否安装成功,Runners中的Url地址①是否正确。

4.2 GitLab CI****乱码问题

GitLab返回信息乱码,一般是因为GitLab不能识别中文,一般乱码是PowerShell返回的中文,把PowerShell脚本独立运行看看是否报错。所以推荐window搞成英文版的,要是哪位大侠知道GitLab怎么识别中文麻烦分享下哈。

4.3 明明错误,但Build成功

错误截图如下,请检查Git环境变量是否配置,PowerShell脚本是否独立为一个文件

4.4 .gitlab-ci.yml****脚本错误

点击Lint,进行脚本验证,参考资料http://docs.gitlab.com/ee/ci/yaml/README.html

注意

image058

感谢


劈荆斩棘:Gitlab 部署 CI 持续集成  感谢这篇文章让我少走了很多弯路

https://juejin.im/post/6887751398499287054?utm\_source=gold\_browser\_extension#heading-3

Gitea 用于构建 Git 局域网服务器,Jenkins 是 CI/CD 工具,用于部署前端项目。

配置 Gitea

下载Gitea,选择一个喜欢的版本,例如 1.13,选择gitea-1.13-windows-4.0-amd64.exe下载。

下载完后,新建一个目录(例如 gitea),将下载的 Gitea 软件放到该目录下,双击运行。

打开localhost:3000就能看到 Gitea 已经运行在你的电脑上了。

点击注册,第一次会弹出一个初始配置页面,数据库选择SQLite3。另外把localhost改成你电脑的局域网地址,例如我的电脑 IP 为192.168.0.118。

![](Gitea + Jenkins 自动构建前端项目并部署到服务器/webp.webp)

![](Gitea + Jenkins 自动构建前端项目并部署到服务器/webp.webp)

填完信息后,点击立即安装,等待一会,即可完成配置。

继续点击注册用户,第一个注册的用户将会成会管理员。

打开 Gitea 的安装目录,找到custom\conf\app.ini,在里面加上一行代码START_SSH_SERVER = true。这时就可以使用 ssh 进行 push 操作了。

8. 如果使用 http 的方式无法克隆项目,请取消 git 代理。

git config –global –unset http.proxygit config –global –unset https.proxy复制代码

配置 Jenkins

需要提前安装 JDK,JDK 安装教程网上很多,请自行搜索。

打开Jenkins下载页面。

安装过程中遇到Logon Type时,选择第一个。

端口默认为 8080,这里我填的是 8000。安装完会自动打开http://localhost:8000网站,这时需要等待一会,进行初始化。

按照提示找到对应的文件(直接复制路径在我的电脑中打开),其中有管理员密码。

6. 安装插件,选择第一个。

创建管理员用户,点击完成并保存,然后一路下一步。

8. 配置完成后自动进入首页,这时点击Manage Jenkins->Manage plugins安装插件。

9. 点击可选插件,输入 nodejs,搜索插件,然后安装。10. 安装完成后回到首页,点击Manage Jenkins->Global Tool Configuration配置 nodejs。如果你的电脑是 win7 的话,nodejs 版本最好不要太高,选择 v12 左右的就行。

创建静态服务器

建立一个空目录,在里面执行npm init -y,初始化项目。

执行npm i express下载 express。

然后建立一个server.js文件,代码如下:

constexpress =require(‘express’)constapp = express()constport =8080app.use(express.static(‘dist’))app.listen(port,() =>{console.log(`Example app listening at http://localhost:${port}\`)})复制代码

它将当前目录下的dist文件夹设为静态服务器资源目录,然后执行node server.js启动服务器。

由于现在没有dist文件夹,所以访问网站是空页面。

不过不要着急,一会就能看到内容了。

自动构建 + 部署到服务器

下载 Jenkins 提供的 demo 项目building-a-multibranch-pipeline-project,然后在你的 Gitea 新建一个仓库,把内容克隆进去,并提交到 Gitea 服务器。

2. 打开 Jenkins 首页,点击新建 Item创建项目。

3. 选择源码管理,输入你的 Gitea 上的仓库地址。

你也可以尝试一下定时构建,下面这个代码表示每 5 分钟构建一次。

选择你的构建环境,这里选择刚才配置的 nodejs。

6. 点击增加构建步骤,windows 要选execute windows batch command,linux 要选execute shell。

输入npm i && npm run build && xcopy .\build\* G:\node-server\dist\ /s/e/y,这行命令的作用是安装依赖,构建项目,并将构建后的静态资源复制到指定目录G:\node-server\dist\ 。这个目录是静态服务器资源目录。

8. 保存后,返回首页。点击项目旁边的小三角,选择build now。

9. 开始构建项目,我们可以点击项目查看构建过程。

10. 构建成功,打开http://localhost:8080/看一下结果。

11. 由于刚才设置了每 5 分钟构建一次,我们可以改变一下网站的内容,然后什么都不做,等待一会再打开网站看看。

12. 把修改的内容提交到 Gitea 服务器,稍等一会。打开网站,发现内容已经发生了变化。

使用 pipeline 构建项目

使用流水线构建项目可以结合 Gitea 的webhook钩子,以便在执行git push的时候,自动构建项目。

点击首页右上角的用户名,选择设置。

添加 token,记得将 token 保存起来。

打开 Jenkins 首页,点击新建 Item创建项目。

4. 点击构建触发器,选择触发远程构建,填入刚才创建的 token。

5. 选择流水线,按照提示输入内容,然后点击保存。

6. 打开 Jenkins 安装目录下的jenkins.xml文件,找到标签,在里面加上-Dhudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true。它的作用是关闭CSRF验证,不关的话,Gitea 的webhook会一直报 403 错误,无法使用。加好参数后,在该目录命令行下输入jenkins.exe restart重启 Jenkins。

7. 回到首页,配置全局安全选项。勾上匿名用户具有可读权限,再保存。

打开你的 Gitea 仓库页面,选择仓库设置。

点击管理 web 钩子,添加 web 钩子,钩子选项选择Gitea。

目标 URL 按照 Jenkins 的提示输入内容。然后点击添加 web 钩子。

11. 点击创建好的 web 钩子,拉到下方,点击测试推送。不出意外,应该能看到推送成功的消息,此时回到 Jenkins 首页,发现已经在构建项目了。

12. 由于没有配置Jenkinsfile文件,此时构建是不会成功的。所以接下来需要配置一下Jenkinsfile文件。将以下代码复制到你 Gitea 项目下的Jenkinsfile文件。jenkins 在构建时会自动读取文件的内容执行构建及部署操作。

pipeline {    agent any    stages {        stage(‘Build’) {            steps {  // window 使用 bat, linux 使用 sh                bat ‘npm i’                bat ‘npm run build’            }        }        stage(‘Deploy’) {            steps {                bat ‘xcopy .\\build\\* D:\\node-server\\dist\\ /s/e/y’ // 这里需要改成你的静态服务器资源目录            }        }    }}复制代码

每当你的 Gitea 项目执行push操作时,Gitea 都会通过webhook发送一个 post 请求给 Jenkins,让它执行构建及部署操作。

小结

如果你的操作系统是 Linux,可以在 Jenkins 打包完成后,使用 ssh 远程登录到阿里云,将打包后的文件复制到阿里云上的静态服务器上,这样就能实现阿里云自动部署了。具体怎么远程登录到阿里云,请看下文中的 《Github Actions 部署到阿里云》 一节。

Github Actions 自动构建前端项目并部署到服务器

如果你的项目是 Github 项目,那么使用 Github Actions 也许是更好的选择。

部署到 Github Page

接下来看一下如何使用 Github Actions 部署到 Github Page。

在你需要部署到 Github Page 的项目下,建立一个 yml 文件,放在.github/workflow目录下。你可以命名为ci.yml,它类似于 Jenkins 的Jenkinsfile文件,里面包含的是要自动执行的脚本代码。

这个 yml 文件的内容如下:

name:BuildandDeployon:# 监听 master 分支上的 push 事件push:branches:-masterjobs:build-and-deploy:runs-on:ubuntu-latest# 构建环境使用 ubuntusteps:-name:Checkoutuses:actions/checkout@v2.3.1with:persist-credentials:false-name:InstallandBuild# 下载依赖 打包项目run:|

          npm install

          npm run build-name:Deploy# 将打包内容发布到 github pageuses:JamesIves/github-pages-deploy-action@3.5.9# 使用别人写好的 actionswith:# 自定义环境变量ACCESS_TOKEN:$# VUE_ADMIN_TEMPLATE 是我的 secret 名称,需要替换成你的BRANCH:masterFOLDER:distREPOSITORY_NAME:woai3c/woai3c.github.io# 这是我的 github page 仓库TARGET_FOLDER:github-actions-demo# 打包的文件将放到静态服务器 github-actions-demo 目录下复制代码

上面有一个ACCESS_TOKEN变量需要自己配置。

打开 Github 网站,点击你右上角的头像,选择settings。

>need-to-insert-img

点击左下角的developer settings。

>need-to-insert-img

在左侧边栏中,单击Personal access tokens(个人访问令牌)。

>need-to-insert-img

单击Generate new token(生成新令牌)。

输入名称并勾选repo。

拉到最下面,点击Generate token,并将生成的 token 保存起来。

打开你的 Github 项目,点击settings。

点击secrets->new secret。

创建一个密钥,名称随便填(中间用下划线隔开),内容填入刚才创建的 token。

将上文代码中的ACCESS_TOKEN: $替换成刚才创建的 secret 名字,替换后代码如下ACCESS_TOKEN: $。保存后,提交到 Github。

以后你的项目只要执行git push,Github Actions 就会自动构建项目并发布到你的 Github Page 上。

Github Actions 的执行详情点击仓库中的Actions选项查看。

具体详情可以参考一下我的 demo 项目**github-actions-demo**。

>need-to-insert-img

构建成功后,打开 Github Page 网站,可以发现内容已经发布成功。

Github Actions 部署到阿里云

初始化阿里云服务器

购买阿里云服务器,选择操作系统,我选的 ubuntu

在云服务器管理控制台选择实例->更多->密钥->重置实例密码(一会登陆用)

选择远程连接->VNC,会弹出一个密码,记住它,以后远程连接要用(ctrl + alt + f1~f6 切换终端,例如 ctrl + alt + f1 是第一个终端)

进入后是一个命令行 输入root(默认用户名),密码为你刚才重置的实例密码

登陆成功, 更新安装源sudo apt-get update && sudo apt-get upgrade -y

安装 npmsudo apt-get install npm

安装 npm 管理包sudo npm install -g n

安装 node 最新稳定版sudo n stable

创建一个静态服务器

mkdir node-server// 创建 node-server 文件夹cd node-server// 进入 node-server 文件夹npm init -y// 初始化项目npm i expresstouch server.js// 创建 server.js 文件vim server.js// 编辑 server.js 文件复制代码

将以下代码输入进去(用 vim 进入文件后按 i 进行编辑,保存时按 esc 然后输入 :wq,再按 enter),更多使用方法请自行搜索。

constexpress =require(‘express’)constapp = express()constport =3388// 填入自己的阿里云映射端口,在网络安全组配置。app.use(express.static(‘dist’))app.listen(port,’0.0.0.0’,() =>{console.log(`listening`)})复制代码

执行node server.js开始监听,由于暂时没有dist目录,先不要着急。

注意,监听 IP 必须为0.0.0.0,详情请看部署Node.js项目注意事项

阿里云入端口要在网络安全组中查看与配置。

创建阿里云密钥对

请参考创建SSH密钥对绑定SSH密钥对,将你的 ECS 服务器实例和密钥绑定,然后将私钥保存到你的电脑(例如保存在 ecs.pem 文件)。

打开你要部署到阿里云的 Github 项目,点击 setting->secrets。

点击 new secret

secret 名称为SERVER_SSH_KEY,并将刚才的阿里云密钥填入内容。

点击 add secret 完成。

在你项目下建立.github\workflows\ci.yml文件,填入以下内容:

name:Buildappanddeploytoaliyunon:#监听push操作push:branches:# master分支,你也可以改成其他分支-masterjobs:build:runs-on:ubuntu-lateststeps:-uses:actions/checkout@v1-name:InstallNode.jsuses:actions/setup-node@v1with:node-version:’12.16.2’-name:Installnpmdependenciesrun:npminstall-name:Runbuildtaskrun:npmrunbuild-name:DeploytoServeruses:easingthemes/ssh-deploy@v2.1.5env:SSH_PRIVATE_KEY:$ARGS:’-rltgoDzvO –delete’SOURCE:dist# 这是要复制到阿里云静态服务器的文件夹名称REMOTE_HOST:’118.190.217.8’# 你的阿里云公网地址REMOTE_USER:root# 阿里云登录后默认为 root 用户,并且所在文件夹为 rootTARGET:/root/node-server# 打包后的 dist 文件夹将放在 /root/node-server复制代码

保存,推送到 Github 上。

以后只要你的项目执行git push操作,就会自动执行ci.yml定义的脚本,将打包文件放到你的阿里云静态服务器上。

这个 Actions 主要做了两件事:

克隆你的项目,下载依赖,打包。

用你的阿里云私钥以 SSH 的方式登录到阿里云,把打包的文件上传(使用 rsync)到阿里云指定的文件夹中。

如果还是不懂,建议看一下我的demo

作者:谭光志

链接:https://juejin.im/post/6887751398499287054

来源:掘金

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

引言

大U的技术课堂 的新年第一课,祝大家新的一年好好学习,天天向上:)

本篇将手把手教你如何快速而优雅的构建前后端分离的项目,想直接上手请往后翻!

目录:

  1. 我为什么要选择Django与VueJS?

  2. Django和VueJS是如何结合起来的?

  3. 实操

  4. 创建 Django 项目

  5. 创建 Django App 做为后端

  6. 创建 VueJS 项目作为前端

  7. 使用 Webpack 处理前端代码

  8. 配置 Django 模板的搜索路径

  9. 配置 Django 静态文件搜索路径

  10. 开发环境

  11. 生产环境(部署到 UCloud)

正文:

我为什么要选择Django与VueJS?

首先介绍一下我看重的点:

Django (MVC框架) - The Web framework for perfectionists with deadlines

  • Python

  • ORM

  • 简单、清晰的配置

  • Admin app

Django 仅因为 Python 的血统,就已经站在了巨人的肩膀上,配置管理( SaltStack、Ansible )
,数据分析( Pandas ),任务队列( Celery ),Restful API( Django REST framework ),HTTP请求( requests ),再加上高度抽象的ORM,功能强大的 Query Expressions,简单清晰的配置,着重提一下堪称神器的自带App: Admin,有了它你再也不用将一些经常变化的配置写在文件里面,每次增删改都重新发布一次,你只需要定义出配置的 data scheme ,只需要几行代码,Django Admin便为你提供美观,并带有权限控制的增删改查界面,而且可以通过ORM为它生成的API来做到定制化的更新,比如直接读某个wiki上的配置,自动的写入数据库,伪代码如下:

1
2
3
4
import pandas as pd
settings = pd.read_html('http://某个gitlab的README 或者 某个redmine wiki')
settings = clean(settings)
update(settings)

最后还可以使用 django-celery 的 celery-beat 按 Interval/crontab 的方式扔更新配置的任务到 celery 队列里面,最最重要的是,这些都可以在Django Admin后台直接配置哦,还不够优雅?请联系我

VueJS (MVVM框架) - Vue.js

  • 数据双向绑定
  • 单文件组件
  • 清晰的生命周期
  • 学习曲线平滑
  • vue-cli

前端是DevOps的弱项,我需要一个 MVVM 框架来提升交互和节约时间,在试过 AngularJS ,ReactJS,VueJS之后我选择了VueJS,因为我觉得写 VueJS 代码的感觉最接近写 Python

着重提一下单文件组件:

特别清晰,一个文件包含且仅包含三块

  1. 前端渲染的模板
  2. 专为此模板写渲染逻辑的
  3. 专为此模板写样式的

这样可以达到什么效果呢?一个文件一个组件,每个组件有它自己的逻辑与样式,你不用关心什么 local 什么 global ,CSS样式加载先后、覆盖问题,因为它是『闭包』的,而且『自给自足』,不知道这样说好不好理解

当然组件之间也是可以通信的,举个例子,我有一个组件叫 ListULB ,使用表格展示了我拥有的所有 ULB (负载均衡),ListULB 做了一件事,从 API 获取 ULB 对象列表并 for 循环展现出来, ListULB 可以放到某个页面里,可以放到弹框里,放到模态框里,任何地方都可以,因为这个组件对外交互的只有API

如果我现在要写一个组件叫 AddVServer ,功能是可以为任意一个 ULB 对象添加VServer,我的写法是将在 AddVServer 组件创建的时候,将 ULB 对象传给 AddVServer 组件,这样AddVServer 组件拿到这个对象,就可以直接根据对象的ID等,创建出当前行的ULB的VServer了,伪代码如下:

1
2
3
4
5
6
<ListULB>
for **ulb_object** in ulbs_list:
{{ ulb_object.name }}
{{ ulb_object.id }}
<AddVServer :current_ulb='**ulb_object**'></AddVServer>
</ListULB>

注意双星号包着的对象,在 ListULB 组件里面是每行的ULB,传给AddServer组件之后,变成了 current_ulb 对象,拿到id为 current_ulb.id 尽情的为它创建 VServer 吧

如果我要为指定 VServer 创建 RServer 呢,一样的

看出来了吧,进行开发之前,前端组件的结构与数据的结构对应起来可以省好多时间,数据驱动前端组件,棒吗?

谁不喜欢优雅的代码呢, 『Data drive everything』 多么的省脑细胞

以上就是我选择Python与VueJS的原因

Django与VueJS是如何结合起来?

  • 首先我选择了VueJS的前端渲染,自然放弃了Django的后端模板引擎渲染
  • 然后业务逻辑放到了前端,放弃了Django的View(其实也就是前后端分离必要的条件)
  • 保留了Django的 Controller (URLconf) 来实现前端路由的父级路由,可以达到不同页面使用不同的前端框架, 页面内部使用各自独有的前端路由的效果,万一老大给你配了前端呢,万一前端只想写 ReactJS 呢
  • 保留了Django的 Model ,前面说了Django的ORM太好用了,而且可以配合Django Admin

所以综合来说就是:

M(Django) + C(Django) + MVVM (VueJS) = M + MVVM + C = MMVVMC

(为了容易理解,并没有使用Django自称的MTV模式理解,感兴趣看看我画的图)

总结:作为以改变世界为己任的 DevOps ,MVC框架后端渲染的柔弱表现力与繁杂的交互已经不能满足我们了,…..省略1000子…..,所以我选择这样构建项目,嗯…

好吧,也该开始了

代码块中的修改都会用爽星号括起来,比如: **changed**

本文为了精简篇幅,默认您已经安装了必要的 命令行界面(CLI),比如 vue-cli等

1. 创建Django项目

命令:

1
django-admin startproject ulb_manager

结构:

1
2
3
4
5
6
7
.
├── manage.py
└── ulb_manager
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py

2. 进入项目根目录,创建一个 app 作为项目后端

命令:

1
2
cd ulb_manager
python manage.py startapp backend

即:app 名叫做 backend

结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.
├── backend
│ ├── __init__.py
│ ├── admin.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── manage.py
└── ulb_manager
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py

3. 使用vue-cli创建一个vuejs项目作为项目前端

命令:

1
vue-init webpack frontend

即:项目名叫 frontend

结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
.
├── backend
│ ├── __init__.py
│ ├── admin.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── frontend
│ ├── README.md
│ ├── build
│ │ └── ....
│ ├── config
│ │ ├── dev.env.js
│ │ ├── index.js
│ │ ├── prod.env.js
│ │ └── test.env.js
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.vue
│ │ ├── assets
│ │ │ └── logo.png
│ │ ├── components
│ │ │ └── Hello.vue
│ │ └── main.js
│ ├── static
│ └── test
│ └── ...
├── manage.py
└── ulb_manager
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py

结构总结:

可以看到项目根目录有两个新文件夹,一个叫 backend ,一个叫 frontend,分别是:

  • backend Django的一个app
  • frontend Vuejs项目

4. 接下来我们使用 webpack 打包Vusjs项目

命令:

1
2
3
cd frontend
npm install
npm run build

结构:

我引入了一些包,比如element-ui等,你的static里面的内容会不同,没关系 index.html 和 static 文件夹相同就够了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
dist
├── index.html
└── static
├── css
│ ├── app.42b821a6fd065652cb86e2af5bf3b5d2.css
│ └── app.42b821a6fd065652cb86e2af5bf3b5d2.css.map
├── fonts
│ ├── element-icons.a61be9c.eot
│ └── element-icons.b02bdc1.ttf
├── img
│ └── element-icons.09162bc.svg
└── js
├── 0.8750b01fa7ffd70f7ba6.js
├── vendor.804853a3a7c622c4cb5b.js
└── vendor.804853a3a7c622c4cb5b.js.map

构建完成会生成一个 文件夹名字叫dist,里面有一个 index.html 和一个 文件夹static ,

5. 使用Django的通用视图 TemplateView

找到项目根 urls.py (即ulb_manager/urls.py),使用通用视图创建最简单的模板控制器,访问 『/』时直接返回 index.html

1
2
3
4
5
urlpatterns = [
url(r'^admin/', admin.site.urls),
**url(r'^$', TemplateView.as_view(template_name="index.html")),**
url(r'^api/', include('backend.urls', namespace='api'))
]

6. 配置Django项目的模板搜索路径

上一步使用了Django的模板系统,所以需要配置一下模板使Django知道从哪里找到index.html

打开 settings.py (ulb_manager/settings.py),找到TEMPLATES配置项,修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
# 'DIRS': [],
**'DIRS': ['frontend/dist']**,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

注意这里的 frontend 是VueJS项目目录,dist则是运行 npm run build 构建出的index.html与静态文件夹 static 的父级目录

这时启动Django项目,访问 / 则可以访问index.html,但是还有问题,静态文件都是404错误,下一步我们解决这个问题

7. 配置静态文件搜索路径

打开 settings.py (ulb_manager/settings.py),找到 STATICFILES_DIRS 配置项,配置如下:

1
2
3
4
# Add for vuejs
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "frontend/dist/static"),
]

这样Django不仅可以将/ulb 映射到index.html,而且还可以顺利找到静态文件

此时访问 /ulb 我们可以看到使用Django作为后端的VueJS helloworld

ALL DONE.

8. 开发环境

因为我们使用了Django作为后端,每次修改了前端之后都要重新构建(你可以理解为不编译不能运行)

除了使用Django作为后端,我们还可以在dist目录下面运行以下命令来看效果:

但是问题依然没有解决,我想过检测文件变化来自动构建,但是构建是秒级的,太慢了,所以我直接使用VueJS的开发环境来调试

毫秒,但是有个新问题,使用VueJS的开发环境脱离了Django环境,访问Django写的API,出现了跨域问题,有两种方法解决,一种是在VueJS层上做转发(proxyTable),另一种是在Django层注入header,这里我使用后者,用Django的第三方包 django-cors-headers 来解决跨域问题

安装

1
pip install django-cors-headers

配置(两步)

1. settings.py 修改

1
2
3
4
5
6
7
8
9
10
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
**'corsheaders.middleware.CorsMiddleware',**
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

这里要注意中间件加载顺序,列表是有序的哦

2. settings.py 添加

1
CORS_ORIGIN_ALLOW_ALL = True

至此,我的开发环境就搭建完成了

9. 生产环境部署(部署到 UCloud )

9.1 创建主机

  1. 注册 UCloud - 专业云计算服务商
  2. 点击左侧的 云主机,然后点击 创建主机
  3. 右侧选择 付费方式,点击 立即购买
  4. 在支付确认页面,点击 确认支付

购买成功后回到主机管理列表,如下所示:

这里注意记住你的外网IP,下面的ip替换成你的

9.2 环境搭建与部署

登录主机,用你刚填写的密码:

ssh root@120.132.**.75

CentOS 系统可以使用 yum 安装必要的包

1
2
3
4
5
6
7
8
# 如果你使用git来托管代码的话
yum install git

# 如果你要在服务器上构建前端
yum install nodejs
yum install npm

yum install nginx

我们使用 uwsgi 来处理 Django 请求,使用 nginx 处理 static 文件(即之前 build 之后 dist 里面的static,这里默认前端已经打包好了,如果在服务端打包前端需要安装nodejs,npm等)

安装uWsgi

1
2
3
yum install uwsgi
# 或者
pip install uwsgi

我们使用配置文件启动uwsgi,比较清楚

uwsgi配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
[uwsgi]
socket = 127.0.0.1:9292
stats = 127.0.0.1:9293
workers = 4
# 项目根目录
chdir = /opt/inner_ulb_manager
touch-reload = /opt/inner_ulb_manager
py-auto-reload = 1
# 在项目跟目录和项目同名的文件夹里面的一个文件
module= inner_ulb_manager.wsgi
pidfile = /var/run/inner_ulb_manager.pid
daemonize = /var/log/inner_ulb_manager.log

nginx 配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
server {
listen 8888;
server_name 120.132.**.75;
root /opt/inner_ulb_manager;
access_log /var/log/nginx/access_narwhals.log;
error_log /var/log/nginx/error_narwhals.log;

location / {
uwsgi_pass 127.0.0.1:9292;
include /etc/nginx/uwsgi_params;
}
location /static/ {
root /opt/inner_ulb_manager/;
access_log off;
}
location ^~ /admin/ {
uwsgi_pass 127.0.0.1:9292;
include /etc/nginx/uwsgi_params;
}
}

/opt/inner_ulb_manager/static 即为静态文件目录,那么现在我们静态文件还在 frontend/dist 怎么办,不怕,Django给我们提供了命令:

先去settings里面配置:

1
STATIC_ROOT = os.path.join(BASE_DIR, "static")

然后在存在manage.py的目录,即项目跟目录执行:

1
python manage.py collectstatic

这样frontend/dist/static里面的东西就到了项目根目录的static文件夹里面了

那么为什么不直接手动把构建好的dist/static拷过来呢,因为开始提过Django自带的App:admin 也有一些静态文件(css,js等),它会一并collect过来,毕竟nginx只认项目跟目录的静态文件,它不知道django把它自己的需求文件放到哪了

开头说过Django配置灵活,那么我们专门为Django创建一个生产环境的配置 prod.py

prod.py 与 默认 settings.py 同目录

1
2
3
4
5
6
7
8
9
10
11
# 导入公共配置
from .settings import *

# 生产环境关闭DEBUG模式
DEBUG = False

# 生产环境开启跨域
CORS_ORIGIN_ALLOW_ALL = False

# 特别说明,下面这个不需要,因为前端是VueJS构建的,它默认使用static作为静态文件入口,我们nginx配置static为入口即可,保持一致,没Django什么事
STATIC_URL = '/static/'

如何使用这个配置呢,进入 wisg.py 即uwsgi配置里面的module配置修改为:

1
2
3
4
5
6
7
import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "**inner_ulb_manager.prod**")

application = get_wsgi_application()

启动uwsgi

1
uwsgi --ini inner_ulb_manager.ini

启动ngingx

至此,部署就完成了

10. 效果图

List 组件:

传单个 ULB 对象给 Detail 组件使用即可

Detail 组件:

当然里面还实现了前面提到的 ULB 的 VServer 创建,VServer 的 RServer 的创建等。

————————

本文由『UCloud平台产品研发团队』提供。

项目源码文件戳下面链接查看,大家可以马上拿源码上手试起来,操作过程中遇到问题也可直接在github上留言:)https://github.com/tmpbook/django-with-vuejs

现在注册使用UCloud,还免费试用 及 首充返现优惠,最高可返3000元代金券!活动传送门:用UCloud!3000元限量版礼盒等你来拆!

另,欢迎添加UCloud运营小妹个人微信号:Surdur,陪聊很专业:)

关于作者:

星辰(@星辰), UCloud平台产品研发工程师,DevOps一枚。你也可以去他的知乎专栏 《随心DevOps》 上逛逛,干货满满,带你更优雅的改变世界。

相关阅读推荐:

机器学习进阶笔记之八 | TensorFlow与中文手写汉字识别

机器学习进阶笔记之七 | MXnet初体验
机器学习进阶笔记之六 | 深入理解Fast Neural Style
机器学习进阶笔记之五 | 深入理解VGG\Residual Network
机器学习进阶笔记之四 | 深入理解GoogLeNet
机器学习进阶笔记之三 | 深入理解Alexnet
机器学习进阶笔记之二 | 深入理解Neural Style
机器学习进阶笔记之一 | TensorFlow安装与入门

「UCloud机构号」将独家分享云计算领域的技术洞见、行业资讯以及一切你想知道的相关讯息。

欢迎提问&求关注 o(*////▽////*)q~

以上。

npm-check

 npm-check 是一个检查依赖包是否存在过期、不正确、未使用等情况的工具。

 全局安装:

npm  install  -g  npm-check

 使用:

npm-check

上述指令会自动检查当前目录下的依赖包情况。

 这里我们重点关注下未使用的依赖包。npm-check 在检查依赖包是否使用时判断的依据是文件中是否存在 require(package) 这条语句,例如:

const lodash = require(‘lodash’);

只要存在这条语句,即使我并未在其它任何地方使用(也就是说这是个无用的包),但是 npm-check 是不会将其判定为未使用的。

 ESLint

为了解决上述存在的这种情况,我们可以借助 ESLint 先去检查代码是否存在未使用的变量(no-unused-vars),这样就可以检查某个包 require 了但并未在后续使用的情况。

全局安装:

npm install -g eslint

编写 .eslintrc.js 配置文件:

 

eslint  –config  .eslintrc.js  ./

执行上述指令便会检查当前目录下的所有代码是否存在定义了但未使用的变量。删除掉未使用的变量(包含对依赖包的引用)之后,再运行 npm-check 便能正确的找出那些在项目中已不再使用的依赖包了。

1
2
3
4
5
6
7
8
9
10
#配置用户名和邮箱
git config --global user.name
git config --global user.email

#中文路径和文件名乱码
git config --global core.quotePath false

#修改commit编码方式
git config --global i18n.commitEncoding utf-8
git config --global i18n.logOutputEncoding