服务器搭建
初始化并下载express依赖
npm init -y
npm i express -s
npm i mongo -s
server.js
const express = require('express'),
app = express(),
path = require('path')
app.get('/',(req,res) => {
// 当访问到 / 时重定向到 /classes 路由
res.redirect('/classes')
})
app.get('/classes',(req,res) => {
// 访问/classes路由,服务器返回html页面
res.sendFile(path.resolve(__dirname + '/classes.html'))
})
app.listen(3000,()=> {
console.log('3000端口被监听了');
})
前端页面搭建
cdn引入 vue、element-ui、axios
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<title>班级管理系统</title>
</head>
<body>
<div id="app">
<h3>班级管理系统</h3>
<el-table :data="tableData" border style="width: 100%">
<el-table-column prop="name" label="姓名" width="180">
</el-table-column>
<el-table-column prop="age" label="年龄" width="180">
</el-table-column>
<el-table-column prop="score" label="分数" width="180">
</el-table-column>
<el-table-column prop="class" label="班级" width="180">
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="primary" size="small" @click="updateRow(scope.row)">编辑</el-button>
<el-button type="danger" size="small" @click.native.prevent="deleteRow(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
new Vue({
el: "#app",
data() {
return {
tableData: [
{
_id: 1,
name: 'Max',
age: 18,
score: 98,
class: 1
}
]
}
},
methods: {
deleteRow(row) {
console.log(row);
},
updateRow(row){
console.log(row);
}
}
})
</script>
</body>
</html>
编写路由、连接接口 和 封装db模块
每个接口都对服务器进行一次连接,对服务器的压力是特别大的,这时就需要对数据库的操作进行封装
创建db文件夹
数据库配置
dbConfig.js 用来存放配置
// 数据库对应的 url 和 名字
module.exports = {
url: 'mongodb://max:123456@192.168.31.67:27017',
dbName: 'classes'
}
封装db模块
index.js 用来配置mongo实例并抛出
const dbConfig = require('./dbConfig'),
MongoClient = require('mongodb').MongoClient,
eventEmitter = require('events')
// 引入事件循环模块来创建emiter
class Mongo{
constructor(dbConfig) {
this.dbConfig = dbConfig
// 实例化事件循环模块
this.emitter = new eventEmitter()
// 创建客户端
this.client = new MongoClient(this.dbConfig.url, {useNewUrlParser:true})
// 建立连接
this.client.connect(err=> {
if(err) throw err
console.log('数据库连接成功');
// 绑定事件循环触发连接操作
this.emitter.emit('connect')
})
}
// 声明调用一次的事件,传入事件名和回调函数
once(eventName,callBack) {
// 上面触发emit,下面绑定on,once表示触发一次
this.emitter.once(eventName, callBack)
}
// 获取集合的方法
// 预留集合名字,如果不传入,默认为classes
col(colName, dbName = this.dbConfig.dbName) {
// 返回 客户端的 数据库 → 集合
return this.client.db(dbName).collection(colName)
}
}
// 抛出Mongo实例并传入配置信息
module.exports = new Mongo(dbConfig)
调用封装模块
server.js 内引入 index.js 抛出的 mongo实例
在路由内链接数据库的集合对象,对数据进行操作
const mongod = require('./db')
app.get('/api/classList', async (req,res) => {
// 链接数据库 获取集合对象
const students = mongod.col('students')
// 调用find()获取所有的数据
const classList = await students.find().toArray()
// 通过json方式返回给前端
res.json({
ok: 1,
classList
})
})
测试数据
tesData.js 模拟前端传入数据,调用mongo实例的once方法连接数据库并写入数据
const mongodb = require('./index.js')
mongodb.onec('connect', async () => {
const students = mongodb.col('students')
try {
// 插入测试数据
await students.deleteMany()
await students.insertMany([
{
name: '张三',
age: 20,
score: 90,
class: 1
},
{
name: '李四',
age: 24,
score: 90,
class: 4
},
{
name: '王五',
age: 21,
score: 96,
class: 7
},
{
name: '赵六',
age: 19,
score: 76,
class: 3
},
{
name: '吴七',
age: 43,
score: 48,
class: 4
},
{
name: '钱八',
age: 38,
score: 79,
class: 4
},
{
name: '孙九',
age: 52,
score: 95,
class: 2
},
{
name: '周十',
age: 46,
score: 49,
class: 1
},
])
console.log('测试数据插入成功');
} catch(err) {
console.log(err.stack);
}
})
在server.js内引入模块,保存,就可以完成数据库操作
const testData = require('./db/testData')
Postman测试接口
打开postman后,新建工作区
创建新的集合
添加一个请求
输入路由信息
点击下方的键,添加提个查询参数,参数会实时反映到路由
分页接口编写
当前列表能显示4条数据,需要获取第二页的内容,路由则写为
http://localhost:3000/api/classList?pageSize=4&pageIndex=2
在后端接口打印 req.query
app.get('/api/classList', async (req,res) => {
// http://localhost:3000/api/classList?pageSize=4&pageIndex=2
console.log(req.query);
})
// { pageSize: '4', pageIndex: '2' }
得到的query解析出了这个请求体的对象,接下来获取这两个属性,传入查询请求,跳过的条数,限制条数,然后返回数据
app.get('/api/classList', async (req,res) => {
// 解构出这两个属性
let {pageSize, pageIndex} = req.query
// 强制将传过来的 string数字 转换为 number数字
pageSize = Number(pageSize)
pageIndex = Number(pageIndex)
// 链接数据库 获取集合对象
const students = mongod.col('students')
// 调用find()传入查询参数,获取对应数据
const classList = await students.find().skip((pageIndex-1) * pageSize).limit(pageSize).toArray()
res.json({
ok: 1,
classList
})
})
到Postman测试一下,获取到了四条数据
{
"ok": 1,
"classList": [
{
"_id": "616a19d385c36df56876d6fe",
"name": "吴七",
"age": 43,
"score": 48,
"class": 4
},
{
"_id": "616a19d385c36df56876d6ff",
"name": "钱八",
"age": 38,
"score": 79,
"class": 4
},
{
"_id": "616a19d385c36df56876d700",
"name": "孙九",
"age": 52,
"score": 95,
"class": 2
},
{
"_id": "616a19d385c36df56876d701",
"name": "周十",
"age": 46,
"score": 49,
"class": 1
}
]
}
前端获取数据
声明所需数据的条数和当前索引,传入到axios请求内,将返回值赋值,完成显示
data() {
return {
tableData: [],
pageIndex: 1,
pageSize: 4,
}
},
methods:{
// 同步化异步操作
async getClassList() {
// 发起ajax请求
const res = await axios.get('/api/classList', {
// 传入参数
params: {
pageIndex: this.pageIndex,
pageSize: this.pageSize
}
})
// 如果返回的状态 ok 等于 1
if(res.data.ok === 1) {
// 赋值给表格数据
this.tableData = res.data.classList
}
},
},
created() {
// 创建组件时即调用方法发起请求
this.getClassList()
}
添加页码组件
组件 绑定 pageIndex 和 pageSize,声明总数状态等待从服务器获取,
<el-pagination
@current-change="handleCurrentChange"
:current-page="pageIndex"
:page-size="pageSize"
layout="total, prev, pager, next, jumper"
:total="total">
</el-pagination>
<script>
data() {
return {
tableData: [],
pageIndex: 1,
pageSize: 4,
total: 0 // 数据总数从数据库获取
}
},
methods: {
// 当点击页码时更改pageIndex并发起请求
handleCurrentChange(val) {
this.pageIndex = val
this.getClassList()
}
}
</script>
请求这里添加total赋值
// 如果返回的状态 ok 等于 1
if(res.data.ok === 1) {
// 赋值给表格数据
this.tableData = res.data.classList
this.total = res.data.total
}
然后是服务器
// 链接数据库 获取集合对象
const students = mongod.col('students')
// 调用find()的count()聚合方法获取数据总数
const total = await students.find().count()
// 调用find()传入查询参数,获取对应数据
const classList = await students.find().skip((pageIndex-1) * pageSize).limit(pageSize).toArray()
res.json({
ok: 1,
classList,
total // 传递给前端
})
刷新页面 数据 和 页码已经正常显示
删除接口编写
server.js
// 从mongodb导出这个方法,用来将前端传来的id字符串转换为mongodb需要的Id对象
const ObjectId = require('mongodb').ObjectId
// 上方加入这条设置,才能通过req.body解析出数据
// 从前端传过来的默认为 x-www-urlencoded 方式进行传输
app.use(express.urlencoded({extended:true}))
// 删除 post 请求
app.post('/api/deleteStudent',async (req, res) => {
const {_id} = req.body
const students = mongod.col('students')
const r = await students.deleteOne({
_id: ObjectId(_id)
})
console.log(r);
res.json({ok: 1})
})
获取一个学生的_id,到postman进行测试,点击发送,返回 ok: 1
server.js终端打印结果
{ acknowledged: true, deletedCount: 1 }
刷新html页面,张三这条数据已经消失
测试完成没有问题修改api
// 删除 post 请求
app.post('/api/deleteStudent',async (req, res) => {
const {_id} = req.body
const students = mongod.col('students')
const r = await students.deleteOne({
_id: ObjectId(_id)
})
// 判断数据库返回 true 则把res返回给前端
if(r.acknowledged === true){
res.json({ok: 1, msg: '删除数据成功'})
}
})
前端删除操作
添加删除方法并绑定到删除按钮上
deleteRow(row){
this.$confirm('此操作将永久删除这个学生, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
// 创建查询参数对象,推入参数
const data = new URLSearchParams()
data.append('_id', row._id)
// 当点击确定按钮则发起ajax请求执行删除操作
const res = await axios.post('/api/deleteStudent', data)
if(res.data.ok === 1) {
// 如果服务器返回 1 则调用查询接口重新获取数据并弹出删除成功信息
this.getClassList()
this.$message({
type: 'success',
message: '删除成功!'
});
}
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
}