帶你學Node系列之express-CRUD

前言

hello,小夥伴們,我是大家的pubdreamcc,本篇博文出至於個人GitHub倉庫node學習教程資料,歡迎小夥伴們點贊和star,大家的點贊是我持續更新的動力。javascript

GitHub倉庫地址:node學習教程html

本篇文章對應的源碼:Student-Management-System前端

好了,廢話很少說了,今天繼續咱們express的學習~java

Student-Management-System

今天咱們實現一個案例,用express實現基本的C-R-U-D(增刪改查)學生信息管理系統。學習這個案例一方面讓咱們熟悉業務開發的流程,一方面能夠鞏固以前學習的express知識。node

文件說明

  • app.js -- 入口模塊git

  • router.js -- 路由模塊github

  • student.js -- 操做數據模塊(封裝操做數據的基本API)數據庫

  • Db.json -- 模擬數據庫,保存數據的文件express

  • views文件夾 -- 頁面視圖文件npm

  • public文件夾 -- 靜態資源文件

啓動

  • git clone 克隆項目到本地

  • npm install 進入項目文件夾,下載相關依賴

  • node app.js node啓動項目

主體設計

  1. 建立public靜態文件夾,views頁面視圖文件夾。

項目中前端頁面使用了bootstrap快速搭建,全部須要開放bootstrap樣式文件和頁面相關的腳本文件。在views文件夾中存放主頁面: index.html,編輯學生信息頁面:edit.html,添加學生頁面:add.html

  1. 建立數據文件Db.json,模擬數據庫存放學生信息數據

由於咱們沒有涉及到數據庫,因此暫時把學生數據存放在Db.json文件中,在數據文件中,咱們須要一個數組:students,用來存放每個學生的信息。一般數據文件都是一個json格式文件,因此嚴格按照json格式要求來模擬數據。

{
  "students": [
    {
      "id": 1,
      "name": "牛魔王",
      "age": 18,
      "hobbies": "打人"
    }
    ...
  ]
}
  1. 建立入口模塊:app.js

在入口模塊中啓動服務器,配置art-template模板引擎,配置express中間件body-parser解析post請求提交的數據,最後把路由容器router掛載到app服務器實例上。由於node中解析代碼是從上至下,因此路由容器掛載必須在各項配置以後,不然會出錯。

const express = require('express')
const router = require('./router')
const bodyParser = require('body-parser')
const app = express()
// 開發靜態資源
app.use('/public/', express.static('./public'))
app.use('/node_modules/', express.static('./node_modules'))
// 配置模板引擎
app.engine('html', require('express-art-template'))
// 配置body-parser,獲得post請求體數據
app.use(bodyParser.urlencoded({ extended: false }))
// 注意:配置模板引擎和body-parser,開放靜態資源必須放在路由容器掛載以前
// 掛載路由容器
app.use(router)
// 綁定端口號,開啓服務
app.listen(3000, () => {
  console.log('running...')
})
  1. 抽取路由模塊router.js,專門處理每一個路由

由於項目中須要處理多個路由,因此咱們分離出一個路由模塊,用來處理路由信息。模塊的分離使得node中每一個模塊各司其職,職能單一,同時也便於後期代碼維護。

router.js模塊中每一個路由都須要涉及到操做數據文件,因此咱們在此以外須要封裝一些數據操做的API。封裝異步 API這裏纔是咱們學習 Node 的精華部分:奧義之所在。

// 路由模塊
const express = require('express')
const Student = require('./student')
// 獲得路由容器
const router = express.Router()
/*
  * 下面就是把每條路由都掛載到路由容器中
*/
// 請求'/',顯示所有學生信息
router.get('/', (req, res) => {
  // 調用Student.find()API,獲取全部學生信息
  。。。
})

// 請求/add',顯示添加學生信息的界面
router.get('/add', (req, res) => {
  res.render('add.html')
})

// 表單post提交數據到'/add',處理數據後重定向至'/'
router.post('/add', (req, res) => {
  /*
    *獲取表單提交的數據
    *添加到數據文件中
    *重定向至首頁,顯示新提交的學生信息
  */
  。。。
})
// 請求'/edit',展現編輯學生信息界面
router.get('/edit', (req, res) => {
  // 調用 Student.findById()API,經過id值獲取學生信息渲染在頁面上
  。。。
})

// 獲取post請求提交的數據,更新學生信息,重定向到'/'
router.post('/edit', (req, res) => {
  /**
   * 獲取新修改的post請求提交的學生信息
   * 處理數據文件,修改學生信息
   * 重定向到'/'
   */
})
// 當請求'/delete',根據id值刪除相應的學生信息,重定向到'/'
router.get('/delete', (req, res) => {
  // 調用 Student.deleteById()API,經過id值查找到對應學生,刪除其信息
  。。。
})

module.exports = router
  1. 封裝數據操做的API,提取數據操做文件模塊student.js

數據操做的模塊,只負責操做數據(增長新數據,修改數據,刪除數據等),不關心業務邏輯。

注意:咱們在操做數據文件的時候,永遠只能是:先讀取出來原有的字符串數據,轉換成對象,處理完成以後,再把對象轉換成JSON格式字符串,最後再保存到數據文件中。文件中永遠存放的是字符串格式的數據

因爲是這種操做順序,因此student.js中頻繁使用到node核心模塊fs,反覆調用fs.readFile()讀取文件內容,fs.writeFile()修改文件中的數據。

// 引入fs核心模塊
const fs = require('fs')
// 保存學生信息
/**
 * 保存新添加的學生信息到數據文件中
 * 參數:
 * 1. 新加的學生信息對象
 * 2. callback回調函數,拿到異步操做的結果
 * callback中的參數:
 * 第一個參數err
 *   成功是null, 失敗是錯誤對象
 *  第二個參數是結果
 *   成功是數組,失敗是undefined
 */
exports.save = (student, callback) => {
  fs.readFile('./Db.json', 'utf8', (err, data) => {
    if (err) {
      return callback(err)
    }
    // 獲得全部學生信息
    let students = JSON.parse(data).students
    // 爲新加的學生添加一個惟一的id屬性(原來最大id屬性值基礎上加1)
    if (students.length === 0) {
      // 若是原始數據文件中沒有學生信息
      student.id = 1
    } else {
      student.id = parseInt(students[students.length-1].id) + 1
    }
    students.push(student)
    // 把新增長學生信息後的對象轉換成字符串保存到數據文件中
    let dataStr = JSON.stringify({
      students: students
    })
    fs.writeFile('./Db.json', dataStr, err => {
      if (err) {
        // 若是寫入失敗,則把錯誤對象傳遞給它
        return callback(err)
      }
      // 成功就沒錯,因此錯誤對象是 null
      callback(null)
    })
  })
}
。。。

因爲篇幅緣由,這裏只羅列了添加學生信息API的實現代碼。這裏還有一個很是重要的知識點:怎樣獲取到一個函數內部異步操做的結果?

只能是經過回調函數。

或許有一些其餘的內置模塊,包括封裝的API也能夠拿到異步操做的結果,可是其底層都是利用了回調函數的思想。好比常見的Node內置events事件模塊等。

  1. 視圖文件編寫

這裏只需強調一點,在編寫視圖文件的時候,須要把一些動態的數據用模板語法包裹起來,可以使得模板引擎正確的渲染模板文件便可。

  1. 啓動服務後看結果(略)

後話

須要學習資料和案例源碼的夥伴能夠去GitHub上查看,若是您對這案例或者學習資料有更好的見解,歡迎issue,或者評論,謝謝。

相關文章
相關標籤/搜索