Express - crud
开发工具
vsCode
起步
初始化模板处理
路由设计
请求方法请求路径get 参数post 参数备注
GET/students渲染首页GET/students/new添加学生页面POST/students/newname、age、gender、hobbies处理添加学生请求GET/students/editid渲染编辑页面POST/students/editid、name、age、gender、hobbies处理编辑学生请求GET/students/deleteid处理删除学生请求
备注配置 art-template 模板引擎
安装
npm install
-S art
-template express
-art
-template
在 Express 获取表单 POST 请求体数据
npm install
-S body
-parser
文件信息
db.json文件 本设计中没有运用数据库开发,所以在此用文件读取的方式来代替数据库,后续再更新增加了数据库的版本。文件内容
{
"students": [
{
"id": 1,
"name": "张三",
"gender": 0,
"age": 18,
"hobbies": "吃饭,睡觉,敲代码"
},
{
"id": 2,
"name": "张三",
"gender": 0,
"age": 18,
"hobbies": "吃饭,睡觉,敲代码"
},
{
"id": 3,
"name": "张三",
"gender": 0,
"age": 18,
"hobbies": "吃饭,睡觉,敲代码"
},
{
"id": 5,
"name": "张三",
"gender": 0,
"age": 18,
"hobbies": "吃饭,睡觉,敲代码"
},
{
"id": 6,
"name": "张三",
"gender": 0,
"age": 18,
"hobbies": "吃饭,睡觉,敲代码"
},
{
"name": "李四",
"gender": "0",
"age": "22",
"hobbies": "敲代码,跳绳",
"id": 8
}
]
}
设计操作数据的文件模块
var fs
= require('fs')
var dbPath
= './db.json'
exports
.find = function (callback
) {
fs
.readFile(dbPath
, 'utf8', function (err
, data
) {
if (err
) {
return callback(err
)
}
callback(null, JSON.parse(data
).students
)
})
}
exports
.findById = function (id
, callback
) {
fs
.readFile(dbPath
, 'utf8', function (err
, data
) {
if (err
) {
return callback(err
)
}
var students
= JSON.parse(data
).students
var ret
= students
.find(function (item
) {
return item
.id
=== parseInt(id
)
})
callback(null, ret
)
})
}
exports
.save = function (student
, callback
) {
fs
.readFile(dbPath
, 'utf8', function (err
, data
) {
if (err
) {
return callback(err
)
}
var students
= JSON.parse(data
).students
student
.id
= students
[students
.length
- 1].id
+ 1
students
.push(student
)
var fileData
= JSON.stringify({
students
: students
})
fs
.writeFile(dbPath
, fileData
, function (err
) {
if (err
) {
return callback(err
)
}
callback(null)
})
})
}
exports
.updateById = function (student
, callback
) {
fs
.readFile(dbPath
, 'utf8', function (err
, data
) {
if (err
) {
return callback(err
)
}
var students
= JSON.parse(data
).students
student
.id
= parseInt(student
.id
)
var stu
= students
.find(function (item
) {
return item
.id
=== student
.id
})
for (var key
in student
) {
stu
[key
] = student
[key
]
}
var fileData
= JSON.stringify({
students
: students
})
fs
.writeFile(dbPath
, fileData
, function (err
) {
if (err
) {
return callback(err
)
}
callback(null)
})
})
}
exports
.deleteById = function (id
, callback
) {
fs
.readFile(dbPath
, 'utf8', function (err
, data
) {
if (err
) {
return callback(err
)
}
var students
= JSON.parse(data
).students
var deleteId
= students
.findIndex(function (item
) {
return item
.id
=== parseInt(id
)
})
students
.splice(deleteId
, 1)
var fileData
= JSON.stringify({
students
: students
})
fs
.writeFile(dbPath
, fileData
, function (err
) {
if (err
) {
return callback(err
)
}
callback(null)
})
})
}
app.js入门模块
var express
= require("express");
var router
= require("./router");
const bodyParser
= require("body-parser");
var app
= express();
app
.use("/public/", express
.static("./public/"));
app
.engine("html", require("express-art-template"));
app
.use(bodyParser
.urlencoded({ extended
: false }));
app
.use(bodyParser
.json());
app
.use(router
);
app
.listen(2000, function () {
console
.log("running 2000......");
});
module
.exports
= app
;
router.js 路由模块
这里的路由模块设计的思想是根据回调函数的思想来设计的。
var fs
= require("fs");
var Student
= require("./student");
var express
= require("express");
var router
= express
.Router();
router
.get("/students", function (req
, res
) {
Student
.find(function (err
, students
) {
if (err
) {
return res
.status(500).send("Server Error!");
}
res
.render("index.html", {
fruits
: ["苹果", "香蕉", "葡萄", "橘子"],
students
: students
,
});
});
});
router
.get("/students/new", function (req
, res
) {
res
.render("new.html");
});
router
.post("/students/new", function (req
, res
) {
Student
.save(req
.body
, function (err
) {
if (err
) {
return res
.status(500).send("Server Error!");
}
res
.redirect("/students");
});
});
router
.get("/students/edit", function (req
, res
) {
Student
.findById(parseInt(req
.query
.id
), function (err
, student
) {
if (err
) {
return res
.status(500).send("Server Error!");
}
res
.render("edit.html", {
student
: student
,
});
});
});
router
.post("/students/edit", function (req
, res
) {
Student
.updateById(req
.body
, function (err
) {
if (err
) {
return res
.status(500).send("Server Error!");
}
res
.redirect("/students");
});
});
router
.get("/students/delete", function (req
, res
) {
Student
.deleteById(req
.query
.id
, function (err
) {
if (err
) {
return res
.status(500).send("Server Error!");
}
res
.redirect("/students");
});
});
module
.exports
= router
;
views页面展示效果
以下这些页面的实现都是在bootstrap官网上找的模板。 链接
https
://v3
.bootcss
.com
/examples
/dashboard
/
index.html首页
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="" />
<meta name="author" content="" />
<title>Dashboard Template for Bootstrap
</title>
<link
rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
/>
<link
href="../../assets/css/ie10-viewport-bug-workaround.css"
rel="stylesheet"
/>
<link rel="stylesheet" href="../public/css/main.css" />
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<button
type="button"
class="navbar-toggle collapsed"
data-toggle="collapse"
data-target="#navbar"
aria-expanded="false"
aria-controls="navbar"
>
<span class="sr-only">Toggle navigation
</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Project name
</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Dashboard
</a></li>
<li><a href="#">Settings
</a></li>
<li><a href="#">Profile
</a></li>
<li><a href="#">Help
</a></li>
</ul>
<form class="navbar-form navbar-right">
<input type="text" class="form-control" placeholder="Search..." />
</form>
</div>
</div>
</nav>
<div class="container-fluid">
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li class="active">
<a href="#">Overview
<span class="sr-only">(current)
</span></a>
</li>
<li><a href="#">Reports
</a></li>
<li><a href="#">Analytics
</a></li>
<li><a href="#">Export
</a></li>
</ul>
<ul class="nav nav-sidebar">
<li><a href="">Nav item
</a></li>
<li><a href="">Nav item again
</a></li>
<li><a href="">One more nav
</a></li>
<li><a href="">Another nav item
</a></li>
<li><a href="">More navigation
</a></li>
</ul>
<ul class="nav nav-sidebar">
<li><a href="">Nav item again
</a></li>
<li><a href="">One more nav
</a></li>
<li><a href="">Another nav item
</a></li>
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">Dashboard
</h1>
<div class="row placeholders">
{{ each fruits }}
<div class="col-xs-6 col-sm-3 placeholder">
<img
src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw=="
width="200"
height="200"
class="img-responsive"
alt="Generic placeholder thumbnail"
/>
<h4>{{ $value }}
</h4>
<span class="text-muted">Something else
</span>
</div>
{{ /each }}
</div>
<h2 class="sub-header">Section title
</h2>
<a class="btn btn-success" href="/students/new">添加学生
</a>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>#
</th>
<th>姓名
</th>
<th>性别
</th>
<th>年龄
</th>
<th>爱好
</th>
<th>操作
</th>
</tr>
</thead>
<tbody>
{{each students}}
<tr>
<td>{{$value.id}}
</td>
<td>{{$value.name}}
</td>
<td>{{$value.gender}}
</td>
<td>{{$value.age}}
</td>
<td>{{$value.hobbies}}
</td>
<td>
<a href="/students/edit?id={{$value.id}}">编辑
</a>
<a href="/students/delete?id={{$value.id}}">删除
</a>
</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
</div>
</div>
</div>
</body>
</html>
new.html添加学生页面
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="" />
<meta name="author" content="" />
<title>Dashboard Template for Bootstrap
</title>
<link
rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
/>
<link
href="../../assets/css/ie10-viewport-bug-workaround.css"
rel="stylesheet"
/>
<link rel="stylesheet" href="../public/css/main.css" />
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<button
type="button"
class="navbar-toggle collapsed"
data-toggle="collapse"
data-target="#navbar"
aria-expanded="false"
aria-controls="navbar"
>
<span class="sr-only">Toggle navigation
</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Project name
</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Dashboard
</a></li>
<li><a href="#">Settings
</a></li>
<li><a href="#">Profile
</a></li>
<li><a href="#">Help
</a></li>
</ul>
<form class="navbar-form navbar-right">
<input type="text" class="form-control" placeholder="Search..." />
</form>
</div>
</div>
</nav>
<div class="container-fluid">
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li class="active">
<a href="#">Overview
<span class="sr-only">(current)
</span></a>
</li>
<li><a href="#">Reports
</a></li>
<li><a href="#">Analytics
</a></li>
<li><a href="#">Export
</a></li>
</ul>
<ul class="nav nav-sidebar">
<li><a href="">Nav item
</a></li>
<li><a href="">Nav item again
</a></li>
<li><a href="">One more nav
</a></li>
<li><a href="">Another nav item
</a></li>
<li><a href="">More navigation
</a></li>
</ul>
<ul class="nav nav-sidebar">
<li><a href="">Nav item again
</a></li>
<li><a href="">One more nav
</a></li>
<li><a href="">Another nav item
</a></li>
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h2 class="sub-header">添加学生
</h2>
<form action="/students/new" method="POST">
<div class="form-group">
<label for="name">姓名
</label>
<input
type="text"
class="form-control"
id="name"
name="name"
placeholder="Email"
/>
</div>
<div class="form-group">
<label>性别
</label>
<div>
<label class="radio-inline">
<input type="radio" name="gender" id="gender1" value="0" /> 男
</label>
<label class="radio-inline">
<input type="radio" name="gender" id="gender2" value="1" /> 女
</label>
</div>
</div>
<div class="form-group">
<label for="age">年龄
</label>
<input type="number" id="age" name="age" class="form-control" />
</div>
<div class="form-group">
<label>爱好
</label>
<input
type="text"
id="hobbies"
name="hobbies"
class="form-control"
/>
</div>
<button type="submit" class="btn btn-default">Submit
</button>
</form>
</div>
</div>
</div>
</body>
</html>
edit.html编辑学生页面
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="" />
<meta name="author" content="" />
<title>Dashboard Template for Bootstrap
</title>
<link
rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
/>
<link
href="../../assets/css/ie10-viewport-bug-workaround.css"
rel="stylesheet"
/>
<link rel="stylesheet" href="../public/css/main.css" />
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<button
type="button"
class="navbar-toggle collapsed"
data-toggle="collapse"
data-target="#navbar"
aria-expanded="false"
aria-controls="navbar"
>
<span class="sr-only">Toggle navigation
</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Project name
</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Dashboard
</a></li>
<li><a href="#">Settings
</a></li>
<li><a href="#">Profile
</a></li>
<li><a href="#">Help
</a></li>
</ul>
<form class="navbar-form navbar-right">
<input type="text" class="form-control" placeholder="Search..." />
</form>
</div>
</div>
</nav>
<div class="container-fluid">
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li class="active">
<a href="#">Overview
<span class="sr-only">(current)
</span></a>
</li>
<li><a href="#">Reports
</a></li>
<li><a href="#">Analytics
</a></li>
<li><a href="#">Export
</a></li>
</ul>
<ul class="nav nav-sidebar">
<li><a href="">Nav item
</a></li>
<li><a href="">Nav item again
</a></li>
<li><a href="">One more nav
</a></li>
<li><a href="">Another nav item
</a></li>
<li><a href="">More navigation
</a></li>
</ul>
<ul class="nav nav-sidebar">
<li><a href="">Nav item again
</a></li>
<li><a href="">One more nav
</a></li>
<li><a href="">Another nav item
</a></li>
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h2 class="sub-header">编辑学生
</h2>
<form action="/students/edit" method="POST">
<input type="hidden" name="id" value="{{student.id}}" />
<div class="form-group">
<label for="name">姓名
</label>
<input
type="text"
class="form-control"
id="name"
name="name"
placeholder="Email"
value="{{student.name}}"
/>
</div>
<div class="form-group">
<label>性别
</label>
<div>
<label class="radio-inline active">
<input type="radio" name="gender" id="gender1" value="0" /> 男
</label>
<label class="radio-inline">
<input type="radio" name="gender" id="gender2" value="1" /> 女
</label>
</div>
</div>
<div class="form-group">
<label for="age">年龄
</label>
<input
type="number"
id="age"
name="age"
class="form-control"
value="{{student.age}}"
/>
</div>
<div class="form-group">
<label>爱好
</label>
<input
type="text"
id="hobbies"
name="hobbies"
class="form-control"
value="{{student.hobbies}}"
/>
</div>
<button type="submit" class="btn btn-default">Submit
</button>
</form>
</div>
</div>
</div>
</body>
</html>
最后有一个需要的css样式
body {
padding-top: 50px
;
}
.sub-header {
padding-bottom: 10px
;
border-bottom: 1px solid #eee
;
}
.navbar-fixed-top {
border: 0
;
}
.sidebar {
display: none
;
}
@media (min-width: 768px) {
.sidebar {
position: fixed
;
top: 51px
;
bottom: 0
;
left: 0
;
z-index: 1000
;
display: block
;
padding: 20px
;
overflow-x: hidden
;
overflow-y: auto
;
background-color: #f5f5f5
;
border-right: 1px solid #eee
;
}
}
.nav-sidebar {
margin-right: -21px
;
margin-bottom: 20px
;
margin-left: -20px
;
}
.nav-sidebar > li > a {
padding-right: 20px
;
padding-left: 20px
;
}
.nav-sidebar > .active > a,
.nav-sidebar > .active > a:hover,
.nav-sidebar > .active > a:focus {
color: #fff
;
background-color: #428bca
;
}
.main {
padding: 20px
;
}
@media (min-width: 768px) {
.main {
padding-right: 40px
;
padding-left: 40px
;
}
}
.main .page-header {
margin-top: 0
;
}
.placeholders {
margin-bottom: 30px
;
text-align: center
;
}
.placeholders h4 {
margin-bottom: 0
;
}
.placeholder {
margin-bottom: 20px
;
}
.placeholder img {
display: inline-block
;
border-radius: 50%
;
}