最近在学Nodejs的基本操作,跟着学习视频做了例子,记录整理下来。
起步(配置模板)
-
安装nodejs
-
新建一个文件夹,作为我们的项目文件夹,以下均在项目文件夹内操作
-
初始化以生成 package.json 文件 (相当于项目的说明书,不可少)
-
新建 app.js 和 public, views 文件夹
app.js 是项目的入口文件,主要用来做各种配置
public 存放各种静态资源
views 存放视图层的 .html 文件
- 安装依赖:express
npm i --save express
- 先写一个最简单的Web服务器测试下
var express = require('express')
var app = express()
app.get('/', function(req, res){
res.send('hello express')
})
app.listen(3000, function(){
console.log('app is running at port 3000')
})
- 公开 public 文件夹中的静态资源,便于.html 文件中用到静态资源
app.use('/public/', express.static('./public/'))
然而上面的Web服务器很傻,只能发送字符串,而我们要实现的目标是当收到浏览器的地址后,向浏览器发送对应显示的页面的 .html 文件。这里使用 art-template 模板引擎
- 在express中使用模板引擎 art-template 达到渲染的目的
- 安装
npm install --save art-template express-art-template
- 在 app.js 配置
app.engine('html', require('express-art-template'))
此方法第一个参数表示,当渲染以 .html 结尾的文件时,使用 art-template模板引擎
- 在 app.js 中使用:express 为 response 相应对象提供了一个方法:render ( )
app.get('/', function(req, res){
res.render('index.html')
//不传参数表示无模板数据
})
第一个参数为 html 模板名, 不写路径,默认会去项目的 views 目录寻找该文件
- 在 views 文件夹下的 index.html 中写模板
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
<th>爱好</th>
</tr>
</thead>
{{each students}}
<tbody>
<th>{{$value.id}}</th>
<th>{{$value.name}}</th>
<th>{{$value.gender}}</th>
<th>{{$value.age}}</th>
<th>{{$value.hobbies}}</th>
</tbody>
{{/each}}
</table>
在 app.js 中渲染
app.get('/students', function(req, res){
fs.readFile('./db.json', 'utf8', function(err, data){
if (err){
return res.status(500).send('Server error.')
}
res.render('index.html', {
students : JSON.parse(data).students
})
})
- 使用 nodemon 自动重启服务
- 安装 (注意需全局安装)
npm i --global nodemon
- 使用
nodemon app.js
提取路由模块
为了代码的模块化,避免冗余,我们将路由模块提取出来单独写在一个 router.js 文件中,并在主入口文件 app.js 中引入:
app.js 中:
var router = require('./router')
app.use(router)
router.js 中:
var express = require ('express')
var router = express.Router()
router.get('/students', function(req, res){
//做一系列操作
})
module.exports = router
这样做完后我们就可在router.js 中尽情写我们的路由了。
接下来,我们先大致规划一下路由
路由表
请求方法 | 请求路径 | GET参数 | POST参数 | 备注 |
---|---|---|---|---|
GET | /students | – | – | 渲染首页 |
GET | /students/new | – | – | 渲染添加页面 |
POST | /students/new | – | name, age, gender | 处理添加学生请求 |
GET | /students/edit | id | – | 渲染编辑页面 |
POST | /students/edit | – | id, name, age, gender | 处理编辑学生请求 |
GET | /students/delete | id | – | 处理删除学生请求 |
上面我们已经完成了渲染首页,接下来依次进行后续操作
封装文件操作函数
我们可以发现,在现在及接下来的一系列操作中,实质上是对 db.json 文件的 增删改查 功能,因此我们想到对这些功能进行封装,方便后面直接调用。
var fs = require ('fs')
var dbpath = './db.json' //自己写的,模拟数据库
/**
* 获取db.json文件内的全部学生信息数据
*/
exports.find = function (callback){
fs.readFile(dbpath, 'utf8', function(err, data){
if (err){
callback(err) //第二个参数不传值默认是undefined
}
callback(null, JSON.parse(data).students)
})
}
封装函数时,为了上层调用时获取其中异步API的结果 ==> 回调函数
在router.js中,我们可以重写渲染首页的代码,直接调用find函数即可
var Students = require('./student')
router.get('/students', function(req, res){
Students.find(function(err, data){
if (err){
return res.status(500).send('Server error.')
}
res.render('index.html', {
students : data
})
})
})
到此,我们可以在接下来的过程中有意识地封装函数。
添加学生信息
当Request以 GET 方式 请求 /students/new时,我们应该渲染添加页面,依然用render函数。
router.js 中:
router.get('/students/new', function(req, res){
res.render('new.html')
})
在 index.html 中添加一个a链接,指向 /students/new
<a href="/students/new">添加学生</a>
new.html(放在 views 文件夹下,将 index.html 中的主体部分换为一个新表单,form 的 action 为 /students/new):
<form action='/students/new'>
//相应表单控件
<button type="submit" class="btn btn-default">Submit</button>
</form>
而当我们点击 提交 按钮后,表单数据将以 POST 方式提交到 /students/new
router.js 中:
router.post('/students/new', function(req, res){
//服务器读取db.json中的数据
//在读到的数组后添加一个新对象,即表单POST请求参数(安装body-parser)
//将新的数组存入db.json中
}
我们有必要利用第三方插件 body-parser 帮助我们获取POST表单数据
- 安装
npm i --save body-parser
- 配置
var bodyParser = require('body-parser')
app.use (bodyParser.urlencoded({extended : false}))
app.use (bodyParser.json())
注意:body-parser 必须写在路由模块前面配置
- 使用
router.post('/students/new', function(req, res){
console.log (req.body)
})
结果如下:
最终封装的函数如下
/**
* 保存新的学生列表
*/
exports.save = function (student, callback){
fs.readFile(dbpath, 'utf8', function(err, data){
if (err){
return callback(err) //一个参数,默认第二个参数是undefined
}
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)
})
})
}
router.js 中
router.post('/students/new', function(req, res){
Students.add_save(req.body, function(err, data){
if (err){
res.status(500).send('Server error.')
}
res.redirect('/students')
})
})
编辑学生信息
首先我们为每个学生都添加一个编辑链接
<th><a href="/students/edit?id={{$value.id}}">编辑</a></th>
router.js 中
//渲染编辑页面
router.get('/students/edit', function(req, res){
Students.findById(req.query.id, function(err, data){
if (err){
res.status(500).send('Server error.')
}
res.render('edit.html', {
student : data
})
})
})
student.js 中
exports.findById = function (id, callback){
fs.readFile(dbpath, 'utf8', function(err, data){
if (err){
callback(err) //第二个参数不传值默认是undefined
}
var students = JSON.parse(data).students
var stu = students.find(function(item){
return parseInt(id)===item.id
})
callback(null, stu)
})
}
可看到如下界面
接下来,我们就可以在页面上进行编辑。
编辑完成后,我们需要将新的数据写入数据库,也就是这里的 db.json 中
student.js 中
/**
* 处理编辑过的学生信息数据
*/
exports.editById = function (student, callback) {
//读数据库所有数据
fs.readFile(dbpath, 'utf8', function (err, data) {
if (err){
callback(err)
}
//将编辑页面上修改的那一项对应修改,并加上id
var students = JSON.parse(data).students
var stu = students.find(function(item){
return parseInt(student.id) === item.id
})
for (var key in stu){
stu[key] = student[key]
}
var fileData = JSON.stringify({
students : students
})
//将修改后的数组对象重新写入
fs.writeFile(dbpath, fileData, function (err){
if (err){
callback(err)
}
callback(null)
})
})
}
router.js 中
router.post('/students/edit', function(req,res){
Students.editById(req.body, function(err, data){
if (err){
res.status(500).send('Server error.')
}
res.redirect('/students')
})
})
删除学生信息
student.js 中
exports.deleteById = function (id, callback){
fs.readFile(dbpath, 'utf8', function (err, data) {
if (err){
callback(err)
}
//将编辑页面上修改的那一项对应修改,并加上id
var students = JSON.parse(data).students
var deleteId = students.findIndex(function(item){
return parseInt(id) === item.id
})
students.splice(deleteId, 1)
var fileData = JSON.stringify({
students : students
})
//将修改后的数组对象重新写入
fs.writeFile(dbpath, fileData, function (err){
if (err){
callback(err)
}
callback(null)
})
})
}
router.js 中
router.get('/students/delete', function(req, res){
Students.deleteById(req.query.id, function(err, data){
if (err){
res.status(500).send('Server error.')
}
res.redirect('/students')
})
})