Node.js学习笔记----day04之学生信息管理系统

认真学习,认真记录,每天都要有进步呀!!!
加油叭!!!


一、起步

项目结构

Node.js学习笔记----day04之学生信息管理系统

  1. 安装需要的包
    Node.js学习笔记----day04之学生信息管理系统
  2. 初始化显示index.html

index.html

var express = require('express')
var app = express()
app.use('/node_modules/', express.static('./node_modules/'))
app.use('/public/', express.static('./public/'))
app.engine('html', require('express-art-template'))
app.get('/',function (req,res) {
   res.render('index.html',{
   	fruit:[
   	'苹果',
   	'香蕉',
   	'橘子'
   	]
   })
 })
app.listen(3000, function () {
  console.log('running 3000...')
})
<!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">
  <link href="/node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 container">
  <h2 class="sub-header">学生信息系统</h2>
<a class="btn btn-success" href="/students/new">添加学生</a>
<table class="table">
  <thead class="thead-light">
    <tr>
      <th scope="col">#</th>
      {{each fruit}}
       <th scope="col">{{$value}}</th>
      {{/each}}
     <!--  <th scope="col">First</th>
      <th scope="col">Last</th>
      <th scope="col">Handle</th> -->
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">1</th>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
    <tr>
      <th scope="row">2</th>
      <td>Jacob</td>
      <td>Thornton</td>
      <td>@fat</td>
    </tr>
    <tr>
      <th scope="row">3</th>
      <td>Larry</td>
      <td>the Bird</td>
      <td>@twitter</td>
    </tr>
  </tbody>
</table>
</div>
</body>
</html>

来吧展示:

Node.js学习笔记----day04之学生信息管理系统

二、从文件中读取数据

  1. 直接写入json数据渲染页面
    app.js
app.get('/',function (req,res) {
   res.render('index.html',{
   	// fruit:[
   	// '苹果',
   	// '香蕉',
   	// '橘子',
   	// ]
   	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":4,"name":"张三","gender":0,"age":18,"hobbies":"吃饭,睡觉,打豆豆"},
	{"id":5,"name":"张三","gender":0,"age":18,"hobbies":"吃饭,睡觉,打豆豆"},
	{"id":6,"name":"张三","gender":0,"age":18,"hobbies":"吃饭,睡觉,打豆豆"}
	]
   })
 })

index.html

<table class="table">
  <thead class="thead-light">
    <tr>
    <th scope="col">id</th>
    <th scope="col">姓名</th>
    <th scope="col">性别</th>
    <th scope="col">年龄</th>
    <th scope="col">兴趣</th> 
    </tr>
  </thead>
  <tbody>
    {{each students}}
    <tr>
      <th scope="row">{{$value.id}}</th>
      <td>{{$value.name}}</td>
      <td>{{$value.gender}}</td>
      <td>{{$value.age}}</td>
      <td>{{$value.hobbies}}</td>
    </tr>
    {{/each}}
   
  </tbody>
</table>

来吧展示:

Node.js学习笔记----day04之学生信息管理系统
2. 通过fs.readFile()读取db.json文件渲染页面

var fs = require('fs')
fs.readFile('./db.json','utf8',function(err,data){
	if(err){
		return res.status(500).send('Server error...')
	}
	console.log(data)
})

打印结果是:
Node.js学习笔记----day04之学生信息管理系统

Node.js学习笔记----day04之学生信息管理系统

app.get('/',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
	   })
    })
})

Node.js学习笔记----day04之学生信息管理系统

三、设计路由

请求方法 请求路径 get 参数 post 参数 备注
GET /studens 渲染首页
GET /students/new 渲染添加学生页面
POST /studens/new name、age、gender、hobbies 处理添加学生请求
GET /students/edit id 渲染编辑页面
POST /studens/edit id、name、age、gender、hobbies 处理编辑请求
GET /students/delete id 处理删除请求

四、把路由都挂载到路由容器中

路由模块的职责
处理路由,根据不同的请求方法 + 路径设置具体的请求处理函数
模块职责要单一,不要乱写
划分模块的目的就是为了增加代码的可维护性,提高开发效率

方式一(不推荐):

Node.js学习笔记----day04之学生信息管理系统

当node执行app.js的时候,页面不能正常显示
Node.js学习笔记----day04之学生信息管理系统
当node执行router.js的时候,页面能正常显示

Node.js学习笔记----day04之学生信息管理系统
方式二(也不推荐)

Node.js学习笔记----day04之学生信息管理系统

Node.js学习笔记----day04之学生信息管理系统
方式三
Express提供了一种更好的方式,专门用来包装路由的

  1. 创建一个路由容器
var router = express.Router()
  1. 把路由都挂载到 router 路由容器中

  2. 把 router 导出

module.exports = router
  1. 把路由容器挂载到 app 服务中
app.use(router)

Node.js学习笔记----day04之学生信息管理系统

来吧展示:

Node.js学习笔记----day04之学生信息管理系统

整合一下 router.js

var fs = require('fs')
var express = require('express')
//1. 创建一个路由容器
var router = express.Router()
//2. 把路由都挂载到 router 路由容器中
router.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
	   })
    })
 })
router.get('/students/new',function (req,res) {
 })
router.post('/students/new',function (req,res) {
 })
router.get('/students/edit',function (req,res) {
 })
router.post('/students/edit',function (req,res) {
 })
router.get('/students/delete',function (req,res) {	
 })
//3. 把 router 导出
module.exports = router

五、处理添加页面以及配置body-parse

  1. 点击添加学生跳转添加页面
    inde.html
<a class="btn btn-success" href="/students/new">添加学生</a>
  1. 渲染添加学生页面

router.js

router.get('/students/new', function (req, res) {
  res.render('new.html')
})
  1. 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">
  <link href="/node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
  <div class="container">
      <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="">姓名</label>
            <input type="text" class="form-control" >
          </div>
          <div class="form-group">
            <label for="">性别</label>
            <div>
              <label class="radio-inline">
                <input type="radio" name="gender"  checked> 男
              </label>
              <label class="radio-inline">
                <input type="radio" name="gender" > 女
              </label>
            </div>
          </div>
          <div class="form-group">
            <label for="">年龄</label>
            <input class="form-control" type="number" >
          </div>
          <div class="form-group">
            <label for="">爱好</label>
            <input class="form-control" type="text" >
          </div>
          <button type="submit" class="btn  btn-success">添加</button>
        </form>
      </div>
  </div>
</body>

</html>

  1. 安装body-parser中间件
    Node.js学习笔记----day04之学生信息管理系统
  2. 配置中间件
    app.js
//引入包
var bodyParser = require('body-parser')

// 配置模板引擎和 body-parser 一定要在 app.use(router) 挂载路由之前
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())

// 把路由容器挂载到 app 服务中
app.use(router)
  1. 查看是否能接收数据
router.get('/students/new', function (req, res) {
  res.render('new.html')
})
router.post('/students/new',function (req,res) {
	console.log(req.body)
 })

来吧展示:

Node.js学习笔记----day04之学生信息管理系统
7. 将数据存入db.json文件用以持久化
先读取出来,转成对象,
然后往数据中push数据
然后将对象转成字符串
然后将字符串再次写入文件

六、封装提取Student数据操作模块

students.js

数据操作文件模块
职责:操作文件中的数据,只处理数据,不关心业务

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)
  })

  
}

router.js

var Student = require('./student')
router.get('/students', function (req, res) {
  Student.find(function (err, students) {
    if (err) {
      return res.status(500).send('Server error.')
    }
    res.render('index.html', {
      students: students
    })
  })
})

七、封装保存学生的API

student.js

exports.save = function (student, callback) {
  fs.readFile(dbPath, 'utf8', function (err, data) {
    if (err) {
      return callback(err)
    }
    var students = JSON.parse(data).students

    // 添加 id ,唯一不重复
    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)
      }
      // 成功就没错,所以错误对象是 null
      callback(null)
    })
  })
}
//处理添加学生
router.post('/students/new', function (req, res) {
  // 1. 获取表单数据
  // 2. 处理
  //    将数据保存到 db.json 文件中用以持久化
  // 3. 发送响应
  Student.save(req.body, function (err) {
    if (err) {
      return res.status(500).send('Server error.')
    }
    res.redirect('/students')
  })
})

来吧展示:
Node.js学习笔记----day04之学生信息管理系统

Node.js学习笔记----day04之学生信息管理系统
Node.js学习笔记----day04之学生信息管理系统

八、完成渲染编辑学生页面

  1. index.html中添加编辑和删除的标签并跳转到相应的页面
   <tr>
    <th scope="col">id</th>
    <th scope="col">姓名</th>
    <th scope="col">性别</th>
    <th scope="col">年龄</th>
    <th scope="col">兴趣</th> 
    <th scope="col">操作</th>
    </tr>
  <tbody>
    {{each students}}
    <tr>
      <th scope="row">{{$value.id}}</th>
      <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>
  1. edit.htmlnew.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">
  <link href="/node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
  <div class="container">
      <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="">姓名</label>
            <input type="text" class="form-control" >
          </div>
          <div class="form-group">
            <label for="">性别</label>
            <div>
              <label class="radio-inline">
                <input type="radio" name="gender"  checked> 男
              </label>
              <label class="radio-inline">
                <input type="radio" name="gender" > 女
              </label>
            </div>
          </div>
          <div class="form-group">
            <label for="">年龄</label>
            <input class="form-control" type="number" >
          </div>
          <div class="form-group">
            <label for="">爱好</label>
            <input class="form-control" type="text" >
          </div>
          <button type="submit" class="btn  btn-success">添加</button>
        </form>
      </div>
  </div>
</body>
</html>
  1. 根据id去获取想要查找的学生信息
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)
  })
}
  1. 渲染编辑学生页面
router.get('/students/edit', function (req, res) {
  // 1. 在客户端的列表页中处理链接问题(需要有 id 参数)
  // 2. 获取要编辑的学生 id
  // 
  // 3. 渲染编辑页面
  //    根据 id 把学生信息查出来
  //    使用模板引擎渲染页面
  Student.findById(parseInt(req.query.id), function (err, student) {
    if (err) {
      return res.status(500).send('Server error.')
    }
    res.render('edit.html', {
      student: student
    })
  })
})
  1. 封装添加保存学生函数
exports.updateById = function (student, callback) {
  fs.readFile(dbPath, 'utf8', function (err, data) {
    if (err) {
      return callback(err)
    }
    var students = JSON.parse(data).students

    // 注意:这里记得把 id 统一转换为数字类型
    student.id = parseInt(student.id)

    // 你要修改谁,就需要把谁找出来
    // EcmaScript 6 中的一个数组方法:find
    // 需要接收一个函数作为参数
    // 当某个遍历项符合 item.id === student.id 条件的时候,find 会终止遍历,同时返回遍历项
    var stu = students.find(function (item) {
      return item.id === student.id
    })
    // 这种方式比较麻烦
    // stu.name = student.name
    // stu.age = student.age

    // 遍历拷贝对象
    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)
      }
      // 成功就没错,所以错误对象是 null
      callback(null)
    })
  })
}
  1. 处理编辑学生保存数据跳转到首页
router.post('/students/edit', function (req, res) {
  // 1. 获取表单数据
  //    req.body
  // 2. 更新
  //    Student.updateById()
  // 3. 发送响应
  Student.updateById(req.body, function (err) {
    if (err) {
      return res.status(500).send('Server error.')
    }
    res.redirect('/students')
  })
})

来吧展示:

Node.js学习笔记----day04之学生信息管理系统
Node.js学习笔记----day04之学生信息管理系统

九、完成删除功能

Node.js学习笔记----day04之学生信息管理系统

exports.deleteById = function (id, callback) {
  fs.readFile(dbPath, 'utf8', function (err, data) {
    if (err) {
      return callback(err)
    }
    var students = JSON.parse(data).students

    // findIndex 方法专门用来根据条件查找元素的下标
    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)
      }
      // 成功就没错,所以错误对象是 null
      callback(null)
    })
  })
}

router.get('/students/delete', function (req, res) {
  // 1. 获取要删除的 id
  // 2. 根据 id 执行删除操作
  // 3. 根据操作结果发送响应数据

  Student.deleteById(req.query.id, function (err) {
    if (err) {
      return res.status(500).send('Server error.')
    }
    res.redirect('/students')
  })
})

来吧展示:

Node.js学习笔记----day04之学生信息管理系统
Node.js学习笔记----day04之学生信息管理系统