代码实例
操作数据库
综合示例如下,设备管理系统(DMS),可以实现通过NodeJS连接MySQL数据库,实现接口,并且可跨域,然后读取到前端页面上。
数据库
使用MySQL数据库,信息如下:
host: 'localhost',
user: 'root',
password: '123456',
database: 'test'
创建 device 表,包含三个字段:id,name,note
前端
html
<!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">
<title>Document</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
<script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.12/index.js"></script>
<script src="https://cdn.bootcss.com/qs/6.5.1/qs.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.js"></script>
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
<div id="app">
<template>
<el-card class="box-card membersTab">
<!-- 查询 -->
<div style="margin-bottom: 40px;">
<el-button @click="getData(input)" style="display: inline-block;" type="primary">查询</el-button>
<el-input style="width: 60%;" v-model="input" placeholder="请输入内容"></el-input>
</div>
<!-- 新增 -->
<div style="margin-bottom: 40px;">
<el-button type="success" @click="handleInsert(id,name,note)">新增</el-button>
<el-input style="width: 20%;" v-model="id" placeholder="请输入id"></el-input>
<el-input style="width: 20%;" v-model="name" placeholder="请输入name"></el-input>
<el-input style="width: 20%;" v-model="note" placeholder="请输入note"></el-input>
</div>
<el-divider></el-divider>
<!-- 数据表格 -->
<el-table
:data="tableData.slice((pageSettings.currentPage-1)*pageSettings.PageSize,pageSettings.currentPage*pageSettings.PageSize)"
stripe style="width: 100%" @sort-change="sortChange">
<el-table-column label="id" width="180" sortable prop="id"></el-table-column>
<el-table-column label="name" width="180" sortable prop="name"></el-table-column>
<el-table-column label="note" width="180" sortable prop="note"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button size="mini" type="danger" @click="handleDelete(scope)">删除</el-button>
<el-button size="mini" type="warning" @click="btn_edit(scope)">编辑</el-button>
</template>
</el-table-column>
</el-table>
<div class="tabListPage">
<el-pagination small @size-change="handleSizeChange" @current-change="handleCurrentChange"
:current-page="pageSettings.currentPage" :page-sizes="pageSettings.pageSizes"
:page-size="pageSettings.PageSize" layout="total, sizes, prev, pager, next, jumper"
:total="pageSettings.totalCount">
</el-pagination>
</div>
<!-- 编辑表单 -->
<el-dialog title="修改信息" :visible.sync="dialogFormVisible">
<el-form :model="form">
<el-form-item label="ID" :label-width="formLabelWidth">
<el-input v-model="form.id" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="NAME" :label-width="formLabelWidth">
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="NOTE" :label-width="formLabelWidth">
<el-input v-model="form.note" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="handleUpdate(form)">确 定</el-button>
</div>
</el-dialog>
</el-card>
</template>
</div>
<script>
const app = new Vue({
el: '#app',
data() {
return {
input: '',
id: '',
name: '',
note: '',
pre_params: '',
dialogFormVisible: false,
formLabelWidth: '120px',
form: {},
tableData: [],
// 分页配置
pageSettings: {
// 分页配置
// 默认显示第几页
currentPage: 1,
// 总条数,根据接口获取数据长度(注意:这里不能为空)
totalCount: 1,
// 个数选择器(可修改)
pageSizes: [3, 5, 10, 20],
// 默认每页显示的条数(可修改)
PageSize: 10,
},
}
},
mounted() {
this.getData()
},
methods: {
// 实现全页面排序
sortChange({ prop, order }) {
this.tableData.sort(this.compare(prop, order));
},
sortChange(column) {
this.pageIndex = 1; // 排序后返回第一页
if (column.order === "descending") {
this.tableData.sort((a, b) => b[column.prop] - a[column.prop]);
} else if (column.order === "ascending") {
this.tableData.sort((a, b) => a[column.prop] - b[column.prop]);
}
},
// 查询
getData() {
let that = this;
axios({
method: 'get',
url: 'http://localhost:8888/query',
params: {
name: that.input
}
}).then(
function (res) {
that.tableData = res.data;
console.log(that.tableData);
// 判断如果存在返回值,则将当前页改为1,否则无法显示内容
if (that.tableData.length > 0) {
that.pageSettings.currentPage = 1
}
// 将数据的长度赋值给totalCount
that.pageSettings.totalCount = that.tableData.length
}
).catch(err => console.log(err))
},
// 功能_新增
handleInsert(param) {
let that = this;
axios({
method: 'post',
url: 'http://localhost:8888/insert',
data: Qs.stringify({
id: that.id,
name: that.name,
note: that.note
})
}).then(
function (res) {
that.getData();
console.log(res);
}
).catch(err => console.log(err));
},
// 功能_删除
handleDelete(param) {
let that = this;
axios({
method: 'post',
url: 'http://localhost:8888/delete',
data: Qs.stringify({
id: param.row.id
})
}).then(
function (res) {
that.getData();
console.log(res.data);
}
).catch(err => console.log(err));
},
// 功能_修改
btn_edit(params) {
this.dialogFormVisible = true;
pre_params = params.row;
console.log(pre_params);
// 将被编辑行的原数据带入到编辑表单
this.form = {
id: pre_params.id,
name: pre_params.name,
note: pre_params.note
}
},
handleUpdate(params) {
let that = this;
console.log(params);
axios({
method: 'post',
url: 'http://localhost:8888/update',
data: Qs.stringify({
id: params.id,
name: params.name,
note: params.note,
pre_params: pre_params
})
}).then(
function (res) {
that.getData();
console.log(res.data);
}
).catch(err => console.log(err));
this.dialogFormVisible = false;
},
// 分页
// 每页显示的条数
handleSizeChange(val) {
// 改变每页显示的条数
this.pageSettings.PageSize = val
// 注意:在改变每页显示的条数时,要将页码显示到第一页
this.pageSettings.currentPage = 1
},
// 显示第几页
handleCurrentChange(val) {
// 改变默认的页数
this.pageSettings.currentPage = val
}
}
})
</script>
<style lang="">
.membersTab {
width: 800px;
margin: 20px auto;
}
</style>
</body>
</html>
后端
js
// 使用expres框架,并创建应用
var express = require('express')
const app = express()
// 解决跨域请求
app.all('*', function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By", ' 3.2.1')
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
// 使用bodyParser中间件
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended: true
}));
// 使用连接池,连接数据库
var mysql = require("mysql");
var pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: '123456',
database: 'test'
});
// DMS.新增
app.post('/insert', (req, res) => {
console.log('-------------------START INSERT---------------------');
console.log(req.body);
const sql = `insert into device(id,name,note) values('${req.body.id}','${req.body.name}','${req.body.note}')`;
console.log(sql);
pool.query(sql, (err, data) => {
if (err) {
console.log(err);
res.send(err)
} else {
res.send(data)
}
})
console.log('-------------------END INSERT---------------------');
})
// DMS.删除
app.post('/delete', (req, res) => {
console.log('-------------------START DELETE---------------------');
console.log(req.body);
// 删除数据
const sql = `delete from device where id = '${req.body.id}'`
console.log(sql);
pool.query(sql, (err, data) => {
if (err) {
console.log(err);
res.send(err)
} else {
res.send(data)
}
})
console.log('-------------------END DELETE---------------------');
})
// DMS.修改
app.post('/update', (req, res) => {
console.log('-------------------START UPDATE---------------------');
console.log(req.body);
// 删除数据
const sql = `update device set id = '${req.body.id}', name = '${req.body.name}', note = '${req.body.note}' where id = '${req.body.pre_params.id}'`
console.log(sql);
pool.query(sql, (err, data) => {
if (err) {
console.log(err);
res.send(err)
} else {
res.send(data)
}
})
console.log('-------------------END UPDATE---------------------');
})
// DMS.查询
app.get('/query', (req, res) => {
console.log('-------------------START QUERY---------------------');
console.log(req.query.name);
// 判断输入框是否为空
if (req.query.name == '' || req.query.name == undefined) {
var sql = 'select * from device order by id'
} else {
// 可改为模糊查询
// var sql = `select * from device where name = '${req.query.name}' order by id`
var sql = `select * from device where name like '%${req.query.name}%' order by id`
}
console.log(sql);
pool.getConnection((err, connection) => {
connection.query(sql, function (err, data) {
console.log(data)
if (err) {
console.log(err);
return;
}
res.send(data)
//释放连接
connection.release();
console.log('-------------------END QUERY---------------------');
});
});
})
// 端口必须要监听
app.listen(8888, () => {
console.log("http://localhost:8888")
})
读取本地文件
// api请求:
// method: "get",
// url: "http://localhost:8081/query",
// params: {
// filename: "input.txt",
// },
// 使用expres框架,并创建应用
const express = require('express');
const app = express();
const fs = require('fs');
// cors解决跨域问题
const cors = require('cors');
app.use(cors());
// 使用bodyParser中间件
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended: true
}));
// 查询
app.get('/query', (req, res) => {
var filename = req.query.filename;
console.log(filename);
// 规定格式:fs.readFile(filename, 'utf-8', (err, data) => {}),如果不指定'utf-8'将解析错误。
fs.readFile(filename, 'utf-8', (err, data) => {
if (err) {
console.log(err);
res.send(err);
} else {
console.log(data);
res.send(data)
}
});
})
// 端口必须要监听
app.listen(8080, () => {
console.log("http://localhost:8080")
})
常见问题处理
跨域问题
使用cors跨域
const cors = require('cors');
app.use(cors());
手动配置
首先,需要定义app,通过express框架
var express = require('express')
const app = express()
解决跨域接收请求
//设置跨域请求
app.all('*', function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By", ' 3.2.1')
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
解决跨域返回
// 使用中间件 允许跨域
// app.use(path,中间件函数)
app.use('/', (req, res, next) => {
// 注意, 需要带 '*'
res.set('Access-Control-Allow-Origin', '*');
next();
});
异步等待
即promise()函数的 async / await 用法。
await必须用在async标记的函数内部。
使用示例如下:
async function write() {
console.log(1);
// 写法1
// await new Promise(function(resolve, reject) {
// setTimeout(function() {
// console.log(2);
// resolve(0);
// }, 2000);
// });
// 写法2
var res = await new Promise((resolve, reject) => {
setInterval(() => {
resolve(2)
}, 1000);
})
console.log(res);
console.log(3);
}
write()
// 输出结果:
// 1
// 2 (1s后执行)
// 3
正常情况依次打印三个数字,由于2被设置了延时,所以应该最后打印2。
但是在使用了 async / await 之后,函数执行顺序必须等待打印2完成后才会执行后续。
res的各方法之间的区别
res.wirte()
必须和res.end()成对出现
res.write() 负责向前端返回数据,res.end() 负责结束请求。如果没有 res.end(),浏览器将会一直处于请求状态。
数据不做处理,原封不动返回
res.write()的返回数据是没有经过处理的,原封不动的返回原数据,所见即所得。
在结束浏览器响应请求之前,允许多次调用
使用 res.write() 可以输出多条语句,即在res.end() 之前可以执行多次,且返回的数据会被拼接到一起。
只允许输出字符串类型和Buffer对象两种数据类型
例如,如果输出数字则会报错。
res.send()
数据会被处理
会自动发送更多的响应报文头,包括返回数据类型,所以不会有乱码。
只允许调用一次
即等同于 res.write() + res.end()
支持多种内容格式
允许String、Array、Buffer对象、对象、json等。
res.json()
同 res.send(),响应结果都是json。
解析参数失败
引入 body-parser 模块,作为中间件
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended: true
}));