准备工作
- 安装Node环境
- 安装Python环境
注意:项目整个过程需要从后往前,即先数据库->后端->前端;启动流程也是先启动后端项目,再启动前端项目
完整项目地址:地址
前端
开发工具:Visual Studio Code(推荐)、WebStorm
打开cmd,安装Vue脚手架,命令如下:
npm install -g @vue/cli
创建Vue2项目,名为
vue-axios
vue create vue-axios
选择
Manually select features
进行创建,回车
目前只勾选
Router
,回车
选择
2.x
,回车
选择如下,回车,等待下载依赖
下载完成后,进入到项目内
cd vue-axios
安装axios库
npm install axios --save
安装Element UI库
npm i element-ui -S
在src下新建utils文件夹,将
request.js
放于src/utils/下,
request.js
是axios的二次封装,如下:
import axios from'axios'const request = axios.create({baseURL:'http://127.0.0.1:666',// 注意!! 这里是全局统一加上了 后端接口前缀 前缀,后端必须进行跨域配置!timeout:5000})// request 拦截器// 可以自请求发送前对请求做一些处理// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config=>{
config.headers['Content-Type']='application/json;charset=utf-8';// config.headers['token'] = user.token; // 设置请求头return config
},error=>{return Promise.reject(error)});// response 拦截器// 可以在接口响应后统一处理结果
request.interceptors.response.use(response=>{let res = response.data;// 如果是返回的文件if(response.config.responseType ==='blob'){return res
}// 兼容服务端返回的字符串数据if(typeof res ==='string'){
res = res ?JSON.parse(res): res
}return res;},error=>{
console.log('err'+ error)// for debugreturn Promise.reject(error)})exportdefault request
修改main.js,进行注册
import Vue from'vue'import App from'./App.vue'import router from'./router'import request from"@/utils/request"import ElementUI from'element-ui';import'element-ui/lib/theme-chalk/index.css';// 关闭生产模式下的提示
Vue.config.productionTip =false// 设置axios为Vue的原型属性Vue.prototype.$axios = request
Vue.use(ElementUI);newVue({
router,render:function(h){returnh(App)}}).$mount('#app')
删除多余的组件,如在src/views和src/components下的vue组件;在src/views新建
Home.vue
组件:
<template>
<div class="home">
<h1>前后端分离小demo</h1>
<!-- 表格区域 -->
<el-table
:data="table"
stripe
:cell-style="{ textAlign: 'center' }"
:header-cell-style="{ textAlign: 'center' }"
>
<el-table-column prop="id" label="ID" width="100" sortable />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="age" label="年龄" />
<el-table-column prop="sex" label="性别" />
<el-table-column label="操作" width="210">
<template slot="header">
<span class="op">操作</span>
<el-button size="mini" class="add" @click="add" icon="el-icon-plus"
>添加一条记录</el-button
>
</template>
<template slot-scope="scope">
<el-button
type="info"
size="mini"
@click="handEdit(scope.$index, scope.row)"
icon="el-icon-edit"
round
>编辑</el-button
>
<el-popconfirm
title="确认删除吗?"
@confirm="handDelete(scope.$index, scope.row)"
>
<el-button
type="danger"
size="mini"
icon="el-icon-delete"
round
slot="reference"
>删除</el-button
>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<!-- 弹出窗 -->
<el-dialog
:title="title"
:visible="dialogVisible"
width="30%"
:before-close="handleClose"
>
<el-form
:model="form"
status-icon
:rules="rules"
ref="form"
label-width="60px"
>
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" autocomplete="off" />
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-input
type="number"
min="1"
max="99"
v-model="form.age"
autocomplete="off"
/>
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-radio-group v-model="form.sex">
<el-radio label="男"></el-radio>
<el-radio label="女"></el-radio>
<el-radio label="未知"></el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="reset">重置</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'Home',
data() {
// 自定义验证规则
var validateAge = (rule, value, callback) => {
if (value === '' || value === undefined) {
callback(new Error('请输入年龄'))
} else if (isNaN(value)) {
callback(new Error('请输入数字'))
} else if (value < 1 || value > 100) {
callback(new Error('年龄必须在1~100之间'))
} else {
callback()
}
}
return {
table: [],
dialogVisible: false,
title: '',
form: {},
rules: {
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
age: [{ required: true, validator: validateAge, trigger: 'blur' }],
sex: [{ required: true, message: '请选择性别', trigger: 'blur' }],
}
}
},
created() {
this.init()
},
methods: {
init() {
this.$axios.get('/all').then(res => {
console.log(res);
this.table = res.data
})
},
add() {
this.dialogVisible = true
this.title = '添加记录'
this.form = {}
},
handEdit(index, row) {
this.dialogVisible = true
this.title = '编辑记录'
this.form = JSON.parse(JSON.stringify(row))
},
handDelete(index, row) {
let id = JSON.parse(JSON.stringify(row)).id
this.$axios.delete(`/delete?id=${id}`).then(res => {
if (res.code == 200) {
this.$notify.success({
title: '成功',
message: res.msg,
duration: 2000
})
this.init()
} else {
this.$notify.success({
title: '失败',
message: res.msg,
duration: 2000
})
}
})
},
handleClose() {
this.dialogVisible = false
this.init()
},
reset() {
let id = undefined
if ('id' in this.form) {
id = this.form.id
}
this.form = {}
if (id != undefined) this.form.id = id
},
save() {
this.$refs['form'].validate(valid => { // 判断是否通过验证
if (valid) {
console.log(this.form);
if ('id' in this.form) {
// console.log('修改');
this.$axios.put('/update', this.form).then(res => {
if (res.code == 200) {
let _this = this
this.$notify.success({
title: '成功',
message: res.msg,
duration: 2000,
onClose: function () { _this.handleClose() }
});
} else {
this.$notify.error({
title: '错误',
message: res.msg,
duration: 2000
});
}
})
} else {
// console.log('添加');
this.$axios.post('/add', this.form).then(res => {
if (res.code == 200) {
let _this = this
this.$notify.success({
title: '成功',
message: res.msg,
duration: 2000,
onClose: function () { _this.handleClose() }
});
} else {
this.$notify.error({
title: '错误',
message: res.msg,
duration: 2000
});
}
})
}
}
})
}
}
}
</script>
<style>
h1 {
text-align: center;
margin: 50px 0;
}
.el-table {
width: 60% !important;
margin: 0 auto;
}
.el-button {
margin: 0 5px;
}
span.op {
display: inline-block;
margin-left: 6px;
}
.el-dialog__body {
padding-bottom: 0;
}
</style>
修改App.vue,如下:
<template>
<div id="app">
<router-view />
</div>
</template>
<style>
/* 引入外部css */
@import "./assets/css/reset.css";
</style>
其中
reset.css
如下:
*{margin: 0;padding: 0;box-sizing: border-box;}
修改src/router/index.js如下:
import Vue from'vue'import VueRouter from'vue-router'
Vue.use(VueRouter)const routes =[{path:'/',name:'home',component:()=>import('@/views/Home.vue')},]const router =newVueRouter({mode:'history',base: process.env.BASE_URL,
routes
})exportdefault router
打开终端或cmd,输入如下命令启动项目
npm run serve
在浏览器输入
http://localhost:8080/
即可打开首页,默认查询全部数据,如下:
添加页面:
编辑页面:
删除页面:
基本的增删改查均已实现,全部采用接口请求的方式进行实现,在开发者工具的网络工具栏下,可以看到前端发送的请求,如下:
以及后端响应数据的预览结果:
后端
开发环境:PyCharm(推荐)、Visual Studio Code
打开cmd,安装flask库,命令如下:
pip install flask
安装flask_cors库,命令如下:
pip install flask_cors
安装pymysql库,命令如下:
pip install pymysql
创建Python项目,名为
python-flask
新建
json_response.py
,统一json返回格式
# 统一的json返回格式classJsonResponse(object):def__init__(self, code, msg, data):
self.code = code
self.msg = msg
self.data = data
# 指定一个类的方法为类方法,通常用self来传递当前类的实例--对象,cls传递当前类。@classmethoddefsuccess(cls, code=200, msg='success', data=None):return cls(code, msg, data)@classmethoddeffail(cls, code=400, msg='fail', data=None):return cls(code, msg, data)defto_dict(self):return{"code": self.code,"msg": self.msg,"data": self.data
}
新建
json_flask.py
,使flask支持返回JsonResponse对象
from flask import Flask, jsonify
from json_response import JsonResponse
classJsonFlask(Flask):defmake_response(self, rv):# 视图函数可以直接返回: list、dict、Noneif rv isNoneorisinstance(rv,(list,dict)):
rv = JsonResponse.success(rv)ifisinstance(rv, JsonResponse):
rv = jsonify(rv.to_dict())returnsuper().make_response(rv)
新建
config.py
,数据库操作
# 数据库操作类import pymysql
DB_CONFIG ={"host":"127.0.0.1","port":3306,"user":"root","passwd":"123456","db":"test","charset":"utf8"}classSQLManager(object):# 初始化实例方法def__init__(self):
self.conn =None
self.cursor =None
self.connect()# 连接数据库defconnect(self):
self.conn = pymysql.connect(
host=DB_CONFIG["host"],
port=DB_CONFIG["port"],
user=DB_CONFIG["user"],
passwd=DB_CONFIG["passwd"],
db=DB_CONFIG["db"],
charset=DB_CONFIG["charset"])
self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)# 查询多条数据defget_list(self, sql, args=None):
self.cursor.execute(sql, args)return self.cursor.fetchall()# 查询单条数据defget_one(self, sql, args=None):
self.cursor.execute(sql, args)return self.cursor.fetchone()# 执行单条SQL语句defmodify(self, sql, args=None):
row = self.cursor.execute(sql, args)
self.conn.commit()return row >0# 执行多条SQL语句defmulti_modify(self, sql, args=None):
rows = self.cursor.executemany(sql, args)
self.conn.commit()return rows >0# 关闭数据库cursor和连接defclose(self):
self.cursor.close()
self.conn.close()
新建
app.py
,主程序
from flask import request
from flask_cors import*from json_flask import JsonFlask
from json_response import JsonResponse
from config import*import json
# 创建视图应用
app = JsonFlask(__name__)# 解决跨域
CORS(app, supports_credentials=True)
db = SQLManager()# 编写视图函数,绑定路由@app.route("/all", methods=["GET"])# 查询(全部)defall():
result = db.get_list(sql='select * from user')return JsonResponse.success(msg='查询成功', data=result)@app.route("/add", methods=["POST"])# 添加(单个)defadd():
data = json.loads(request.data)# 将json字符串转为dict
isOk = db.modify(sql='insert into user(name,age,sex) values(%s,%s,%s)',
args=[data['name'], data['age'], data['sex']])return JsonResponse.success(msg='添加成功')if isOk else JsonResponse.fail(msg='添加失败')@app.route("/update", methods=["PUT"])# 修改(单个)defupdate():
data = json.loads(request.data)# 将json字符串转为dictif'id'notin data:return JsonResponse.fail(msg='需要传入id')
isOk = db.modify(sql='update user set name=%s,age=%s,sex=%s where id=%s',
args=[data['name'], data['age'], data['sex'], data['id']])return JsonResponse.success(msg='修改成功')if isOk else JsonResponse.fail(msg='修改失败')@app.route("/delete", methods=["DELETE"])# 删除(单个)defdelete():if'id'notin request.args:return JsonResponse.fail(msg='需要传入id')
isOk = db.modify(sql='delete from user where id=%s', args=[request.args['id']])return JsonResponse.success(msg='删除成功')if isOk else JsonResponse.fail(msg='删除失败')# 运行flask:默认是5000端口,此处设置端口为666if __name__ =='__main__':
app.run(host="0.0.0.0", port=666, debug=True)
启动项目。
数据库
采用MySQL,由于是小demo,此处设计较简单,数据库名为
test
,表名为
user
,表结构和数据SQL语句如下:
SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS =0;-- ------------------------------ Table structure for user-- ----------------------------DROPTABLEIFEXISTS`user`;CREATETABLE`user`(`id`int(11)NOTNULLAUTO_INCREMENT,`name`varchar(255)CHARACTERSET gbk COLLATE gbk_chinese_ci NOTNULL,`age`int(11)NOTNULL,`sex`varchar(255)CHARACTERSET gbk COLLATE gbk_chinese_ci NOTNULL,PRIMARYKEY(`id`)USINGBTREE)ENGINE=InnoDBAUTO_INCREMENT=11CHARACTERSET= gbk COLLATE= gbk_chinese_ci ROW_FORMAT = Compact;-- ------------------------------ Records of user-- ----------------------------INSERTINTO`user`VALUES(1,'tom',20,'男');INSERTINTO`user`VALUES(2,'mary',20,'女');INSERTINTO`user`VALUES(3,'jack',21,'男');INSERTINTO`user`VALUES(5,'test',20,'未知');INSERTINTO`user`VALUES(8,'tom',20,'男');INSERTINTO`user`VALUES(9,'add',20,'未知');INSERTINTO`user`VALUES(10,'Saly',11,'女');SET FOREIGN_KEY_CHECKS =1;
版权归原作者 杼蛘 所有, 如有侵权,请联系我们删除。