上一篇写到了安装 mysql,基本的 mysql 的命令行操作,以及使用 Node.js 连接 mysql 数据库,今天这篇使用 koa 来操作 mysql,实现基本的增删改查操作。
在上一篇新建的项目下,新建一个server
目录,表示这是服务端提供给页面的接口服务,然后在新建一个static
目录用来放前端的html js css等静态资源文件
,这个static
目录也可以是采用模板,比如pug
等,也可以是前端经过webpack打包之后的使用react或者vue框架开发的页面
,这里我直接是写的最原始的html
页面,原生js
操作页面交互,没有使用任何库,因为本文的重点不在前端,而是操作mysql
,所以使用最简单,最原始的前端方式。下面进入正题。
前端页面部分
static
目录下新建一个index.html
,这里面主要是调用接口,根据返回的数据显示到页面上,出于简单考虑,直接将 js 的操作和 css 样式全部写到 index.html 中,请求使用的原生的fetch
请求,下面是源码:
// static/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>koa+mysql实现增删改查操作</title>
<style>
html *{
padding:0;
margin:0;
border:0;
}
body{
position: relative;
height: 100%;
}
body div{
box-sizing: border-box;
}
input{
border:1px solid #66cded;
line-height: 32px;
font-size: 14px;
margin-bottom: 20px;
padding: 0 5px;
}
button{
border: 1px solid #3eacff;
background: #3eacff;
color:#fff;
font-size: 14px;
line-height: 30px;
padding:5px 10px;
margin-left: 50px;
}
hr{
border-bottom: 1px solid #ccc;
margin: 20px 0;
}
a{
color: #3eacff;
background: transparent;
text-decoration: none;
outline: none;
cursor: pointer;
}
a:hover{
color: #0c8cee;
}
#app{
width: 1200px;
margin: 0 auto;
padding-top: 20px;
}
.title{
font-weight: bold;
color: rgba(0,0,0,.85);
font-size: 16px;
}
.table-row{
border-collapse: collapse;
width: 100%;
}
.table-row thead tr{
background: #e4f3ff;
color:rgba(0,0,0,.85);
}
.table-row td{
border: 1px solid #ccc;
padding: 10px 20px;
text-align: center;
}
.mr15{
margin-right: 15px;
}
.mb15{
margin-bottom: 15px;
}
.modal{
position: fixed;
left: 0;
top:0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
background: rgba(55,55,55,.6);
}
.modal-form{
position: absolute;
background: #fff;
padding: 40px 20px;
top: 50%;
left: 50%;
width: 400px;
color: #000;
margin-left: -200px;
margin-top: -100px;
text-align: center;
}
#close{
position: absolute;
top: 0;
right: 0;
color: #000;
background: #fff;
border: 1px solid #ccc;
}
</style>
</head>
<body>
<div id="app">
<p class="mb15 title">添加数据</p>
<form>
<p><label for="name">name: </label><input type="text" id="name" /></p>
<p><label for="status">status: </label><input type="text" id="status" /></p>
<p><button id="addBtn">添加数据</button></p>
</form>
<hr />
<p class="mb15 title">显示表的数据</p>
<div id="showData"></div>
<hr />
<p class="mb15 title">显示一条数据的详情信息</p>
<div id="detail"></div>
<div id="modal" style="display: none;" class="modal">
<form class="modal-form">
<p><label for="name">name: </label><input type="text" id="edit_name" /></p>
<p><label for="status">status: </label><input type="text" id="edit_status" /></p>
<p><button id="edit_btn">提交修改</button></p>
<button id="close">关闭</button>
</form>
</div>
</div>
<script>
var showData = document.getElementById('showData');
var addBtn = document.getElementById('addBtn');
var detail = document.getElementById('detail');
var edit_btn = document.getElementById('edit_btn');
var modal = document.getElementById('modal');
var close = document.getElementById('close');
var ID = '';
function getList(){
fetch('/getList')
.then((res) => {
return res.json();
})
.then((data) => {
let str = '<table class="table-row" id="tableRow"><thead><tr><td>ID</td><td>name</td><td>status</td><td>操作</td></tr></thead><tbody>';
data.data.forEach(item => {
str += '<tr><td>' + item.id + '</td><td>' + item.name + '</td><td>' + item.status + '</td><td><a href="javascript:;" class="detail mr15" data-id='+item.id+'>详情</a><a href="javascript:;" class="edit mr15" data-item='+JSON.stringify(item)+'>编辑</a><a href="javascript:;" class="delete" data-id='+item.id+'>删除</a></td></tr>';
});
str += '</tbody></table>';
showData.innerHTML = str;
});
}
getList();
function add(){
var name = document.getElementById('name').value;
var status = document.getElementById('status').value;
var params = {
name: name,
status: status
}
fetch('/add', {
method: 'POST',
body: JSON.stringify(params)
})
.then((res) => {
return res.json()
})
.then((data) => {
if(data.code === 200){
getList();
}
})
}
addBtn.onclick = function(e){
e.preventDefault();
add();
};
function deleteData(id){
fetch('/delete', {
method: 'POST',
body: JSON.stringify({id: id})
})
.then((res) => {
return res.json()
})
.then((data) => {
if(data.code === 200){
getList();
}
})
}
function getInfo(id){
fetch('/getInfo/'+id)
.then((res) => {
return res.json()
})
.then((resp) => {
var data = resp.data;
var str= 'ID 为'+ data.id+ '的详细数据如下:'+'<br />';
if(resp.code == 200){
str += 'ID:'+ data.id + '<br />';
str += 'name:'+ data.name + '<br />';
str += 'status:'+ data.status + '<br />';
} else {
str += resp.message;
}
detail.innerHTML = str;
})
}
function updateData(id, name, status){
fetch('/update', {
method: 'POST',
body: JSON.stringify({id: id, name: name, status: status})
})
.then((res) => {
return res.json()
})
.then((data) => {
console.log(data);
modal.style.display = 'none';
if(data.code === 200){
getList();
}
})
}
showData.onclick = function(e){
var target = e.target.className;
var item = JSON.parse(e.target.getAttribute('data-item'));
if(target.indexOf('edit') > -1){
modal.style.display = 'block';
document.getElementById('edit_name').value = item.name;
document.getElementById('edit_status').value = item.status;
ID = item.id;
} else if(target.indexOf('delete') > -1){
const id = e.target.getAttribute('data-id');
deleteData(id);
} else if(target.indexOf('detail') > -1){
const id = e.target.getAttribute('data-id');
getInfo(id);
}
}
edit_btn.onclick = function(e){
e.preventDefault();
var edit_name = document.getElementById('edit_name').value;
var edit_status = document.getElementById('edit_status').value;
updateData(ID, edit_name, edit_status);
}
close.onclick = function(e){
e.preventDefault();
modal.style.display = 'none';
}
</script>
</body>
</html>
server端服务部分
安装依赖库,跑起服务
这里选用的 Node.js 框架是 koa
,路由是koa-router
,koa-static
是 koa 静态文件服务中间件,post 方式提交获取参数使用 koa-body
,需要安装这些库。没安装 mysql
的,也需要安装。
npm i koa koa-router koa-static koa-body mysql -S
安装完成之后可以安装 nodemon
,在每次修改代码之后,无需重启服务:npm i nodemon -S
接下来在 server 目录下新建一个 index.js
,写入如下代码,然后运行 nodemon server/index.js
,先将服务跑起来:
// server/index.js
const Koa = require('koa');
const static = require('koa-static');
const app = new Koa();
const staticPath = '../static';
app.use(static(
join(__dirname, staticPath)
));
app.listen(4455);
console.log('listen at 4455');
可以看到页面如下,还没有数据填充:
获取表数据
现在继续完善 index.js
,先获取到表的数据。
server
目录下新建mysql_config.js
,用来写 mysql 的连接需要的 mysql 配置信息:
module.exports = {
mysql: {
host: 'localhost',
user: 'root',
password: '123456',
database: 'koa_test'
}
}
在新建一个db.js
用来连接数据库,因为数据库的读取写入也是异步的,代码中先连接数据库,获取一个 mysql 的连接,然后使用 promise
封装一下 query
操作,这样后续我们可以使用await
关键字来同步的写代码,异步获取到结果,代码如下:
// server/db.js
const mysql = require('mysql');
const config = require('./mysql_config');
const conn = mysql.createConnection(config.mysql);
conn.connect((err) => {
if(err){
throw err;
}
console.log('mysql 连接成功');
});
let query = (sql, params) => {
return new Promise((resolve, reject) => {
conn.query(sql, params, (error, result, fields) => {
if(error){
reject(error);
} else {
resolve(result);
}
})
})
}
//关闭连接
//conn.end();
module.exports = { conn, query};
接下来我们就让页面的数据表先显示出来吧,在index.js
中写入如下代码,我们直接上完整的代码,不上代码片段,以防看到的同学根据片段跑不起来服务。下面的代码主要是koa-router
路由配置,然后查询数据表domian
的数据,sql 语句 await query('SELECT * FROM domain;')
,:
// server/index.js
const Koa = require('koa');
const static = require('koa-static');
const Router = require('koa-router');
const { join } = require('path');
const { query } = require('./db');
const app = new Koa();
const router = new Router();
const staticPath = '../static';
app.use(static(
join(__dirname, staticPath)
));
app.use(router.routes()).use(router.allowedMethods());
router.get('/getList', async (ctx, next) => {
ctx.type = 'Content-Type: application/json;charset=utf-8';
let result = await query('SELECT * FROM domain;');
let list = [];
result.forEach(item => {
list.push({
id: item.id,
name: item.name,
status: item.status
})
});
console.log(list);
ctx.body = {
code: 200,
data: list,
message: 'getList success'
};
});
app.listen(4455);
console.log('listen at 4455');
nodemon
会根据文件变化重新启动服务,现在我们刷新页面,可以看到数据表出来了:
添加一条数据到表中
数据列表我们拿到了,现在添加一条数据到表里,使用koa-body
,获取post
的body
参数,sql语句是这样的await query('INSERT INTO domain SET ?', JSON.parse(postData));
这是 mysql 模块的语法。index.js
向表中添加数据的完整代码如下:
//server/index.js
const Koa = require('koa');
const static = require('koa-static');
const Router = require('koa-router');
const koaBody = require('koa-body');
const { join } = require('path');
const { query } = require('./db');
const app = new Koa();
const router = new Router();
const staticPath = '../static';
app.use(koaBody());
app.use(static(
join(__dirname, staticPath)
));
app.use(router.routes()).use(router.allowedMethods());
router.get('/getList', async (ctx, next) => {
ctx.type = 'Content-Type: application/json;charset=utf-8';
let result = await query('SELECT * FROM domain;');
let list = [];
result.forEach(item => {
list.push({
id: item.id,
name: item.name,
status: item.status
})
});
console.log(list);
ctx.body = {
code: 200,
data: list,
message: 'getList success'
};
});
router.post('/add', async (ctx, next) => {
const postData = ctx.request.body;
console.log('postData:',JSON.parse(postData));
ctx.type = 'Content-Type: application/json;charset=utf-8';
await query('INSERT INTO domain SET ?', JSON.parse(postData));
ctx.body = {
code: 200,
data: [],
message: 'add success'
};
})
app.listen(4455);
console.log('listen at 4455');
现在我们在页面上添加一条数据,从列表中可以看到数据被添加进去了:
修改表中的某一条数据
接下来我们修改数据,sql 语句是这样的:await query('UPDATE domain SET name = ?, status = ? WHERE id = ?;',[pdata.name, pdata.status, pdata.id]);
,我们把刚刚添加的一条数据修改一下内容,点页面的编辑,弹出 modal 层来修改数据,完整代码如下:
// server/index.js
const Koa = require('koa');
const static = require('koa-static');
const Router = require('koa-router');
const koaBody = require('koa-body');
const { join } = require('path');
const { query } = require('./db');
const app = new Koa();
const router = new Router();
const staticPath = '../static';
app.use(koaBody());
app.use(static(
join(__dirname, staticPath)
));
app.use(router.routes()).use(router.allowedMethods());
router.get('/getList', async (ctx, next) => {
ctx.type = 'Content-Type: application/json;charset=utf-8';
let result = await query('SELECT * FROM domain;');
let list = [];
result.forEach(item => {
list.push({
id: item.id,
name: item.name,
status: item.status
})
});
console.log(list);
ctx.body = {
code: 200,
data: list,
message: 'getList success'
};
});
router.post('/add', async (ctx, next) => {
const postData = ctx.request.body;
console.log('postData:',JSON.parse(postData));
ctx.type = 'Content-Type: application/json;charset=utf-8';
await query('INSERT INTO domain SET ?', JSON.parse(postData));
ctx.body = {
code: 200,
data: [],
message: 'add success'
};
})
router.post('/update', async (ctx, next) => {
const postData = ctx.request.body;
console.log('update postData:', JSON.parse(postData));
const pdata = JSON.parse(postData);
await query('UPDATE domain SET name = ?, status = ? WHERE id = ?;',[pdata.name, pdata.status, pdata.id]);
ctx.type = 'Content-Type: application/json;charset=utf-8';
ctx.body = {
code: 200,
data: [],
message: 'update success'
}
})
app.listen(4455);
console.log('listen at 4455');
原始的显示数据,
现在修改数据:
提交修改,可以看出数据表中的数据确实被修改了:
删除一条数据
现在我们把刚修改的数据给删除吧,sql 语句是这样的:await query('DELETE FROM domain where id=' + JSON.parse(postData).id);
,完整代码如下:
// server/index.js
const Koa = require('koa');
const static = require('koa-static');
const Router = require('koa-router');
const koaBody = require('koa-body');
const { join } = require('path');
const { query } = require('./db');
const app = new Koa();
const router = new Router();
const staticPath = '../static';
app.use(koaBody());
app.use(static(
join(__dirname, staticPath)
));
app.use(router.routes()).use(router.allowedMethods());
router.get('/getList', async (ctx, next) => {
ctx.type = 'Content-Type: application/json;charset=utf-8';
let result = await query('SELECT * FROM domain;');
let list = [];
result.forEach(item => {
list.push({
id: item.id,
name: item.name,
status: item.status
})
});
console.log(list);
ctx.body = {
code: 200,
data: list,
message: 'getList success'
};
});
router.post('/add', async (ctx, next) => {
const postData = ctx.request.body;
console.log('postData:',JSON.parse(postData));
ctx.type = 'Content-Type: application/json;charset=utf-8';
await query('INSERT INTO domain SET ?', JSON.parse(postData));
ctx.body = {
code: 200,
data: [],
message: 'add success'
};
})
router.post('/update', async (ctx, next) => {
const postData = ctx.request.body;
console.log('update postData:', JSON.parse(postData));
const pdata = JSON.parse(postData);
await query('UPDATE domain SET name = ?, status = ? WHERE id = ?;',[pdata.name, pdata.status, pdata.id]);
ctx.type = 'Content-Type: application/json;charset=utf-8';
ctx.body = {
code: 200,
data: [],
message: 'update success'
}
})
router.post('/delete', async (ctx, next) => {
ctx.type = 'Content-Type: application/json;charset=utf-8';
const postData = ctx.request.body;
console.log('delete postData:', JSON.parse(postData));
await query('DELETE FROM domain where id=' + JSON.parse(postData).id);
ctx.body = {
code: 200,
data: [],
message: 'delete success'
}
});
app.listen(4455);
console.log('listen at 4455');
现在点击列表删除刚添加的那一条数据,可以看到数据被删除了:
获取某一条数据的详细信息
最后我们来获取某一条数据的详细信息吧,sql 语句是这样的:await query('SELECT * FROM domain WHERE id = ?;', ctx.params.id)
,完整代码如下:
// server/index.js
const Koa = require('koa');
const static = require('koa-static');
const Router = require('koa-router');
const koaBody = require('koa-body');
const { join } = require('path');
const { query } = require('./db');
const app = new Koa();
const router = new Router();
const staticPath = '../static';
app.use(koaBody());
app.use(static(
join(__dirname, staticPath)
));
app.use(router.routes()).use(router.allowedMethods());
router.get('/getList', async (ctx, next) => {
ctx.type = 'Content-Type: application/json;charset=utf-8';
let result = await query('SELECT * FROM domain;');
let list = [];
result.forEach(item => {
list.push({
id: item.id,
name: item.name,
status: item.status
})
});
console.log(list);
ctx.body = {
code: 200,
data: list,
message: 'getList success'
};
});
router.post('/add', async (ctx, next) => {
const postData = ctx.request.body;
console.log('postData:',JSON.parse(postData));
ctx.type = 'Content-Type: application/json;charset=utf-8';
await query('INSERT INTO domain SET ?', JSON.parse(postData));
ctx.body = {
code: 200,
data: [],
message: 'add success'
};
})
router.post('/update', async (ctx, next) => {
const postData = ctx.request.body;
console.log('update postData:', JSON.parse(postData));
const pdata = JSON.parse(postData);
await query('UPDATE domain SET name = ?, status = ? WHERE id = ?;',[pdata.name, pdata.status, pdata.id]);
ctx.type = 'Content-Type: application/json;charset=utf-8';
ctx.body = {
code: 200,
data: [],
message: 'update success'
}
})
router.post('/delete', async (ctx, next) => {
ctx.type = 'Content-Type: application/json;charset=utf-8';
const postData = ctx.request.body;
console.log('delete postData:', JSON.parse(postData));
await query('DELETE FROM domain where id=' + JSON.parse(postData).id);
ctx.body = {
code: 200,
data: [],
message: 'delete success'
}
});
router.get('/getInfo/:id', async (ctx, next) => {
ctx.type = 'Content-Type: application/json;charset=utf-8';
let result = await query('SELECT * FROM domain WHERE id = ?;', ctx.params.id);
console.log('详情数据:',result);
ctx.body = {
code: 200,
data: result[0],
message: 'getInfo success'
};
})
app.listen(4455);
console.log('listen at 4455');
点击数据表中的一条数据详情,然后显示详情到页面:
最后,mysql 的基本操作就算完成了,到获取详情这里已经是 index.js 的全部代码了。
代码调试
再说一下代码调试,如果在写代码的过程中,遇到问题,如何调试呢。
前端页面发起请求之后,node js代码在接收到请求之后进到断点那里,这样就可以调试了,具体调试方式就是,在启动服务的时候加上--inspect-brk 参数,然后打开chrome浏览器输入:chrome://inspect/#devices
,然后点击页面出现的Open dedicated DevTools for Node
这个文字,会新打开一个chrome DevTools,这就跟浏览器的调试一样的,server的代码也会在Sources里面找到,下面我们演示一下:
1.首先在运行命令node --inspect-brk server/index.js
,可以看到如下信息:
2.浏览器输入chrome://inspect/#devices
,点击Open dedicated DevTools for Node
:
3.点击之后会弹出如下的调试面板,然后在想要调试的地方打上断点即可:
4.现在刷新跑服务的浏览器http://localhost:4455/
,然后添加一条数据,在上一步的调试面板中给add方法
打上断点,可以看到代码就进来了,然后就一步步往下调试就可以了。
以上遇到问题最多的还是写 mysql 语句,直接命令行操作 mysql 没问题,主要是代码操作就需要查 sql 的写法,具体 mysql 的一些写法可以上 npm 找到 mysql 模块看一下。