1. 程式人生 > >express-CRUD

express-CRUD

入口檔案

/**
 * app.js 入門模組
 * 職責:
 *   建立服務
 *   做一些服務相關配置
 *     模板引擎
 *     body-parser 解析表單 post 請求體
 *     提供靜態資源服務
 *   掛載路由
 *   監聽埠啟動服務
 */

var express = require('express')
var router = require('./router')
var bodyParser = require('body-parser')

var app = express()

app.use('/node_modules/', express.static('./node_modules/'))
app.use('/public/', express.static('./public/'))

app.engine('html', require('express-art-template'))

// 配置模板引擎和 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)

app.listen(3000, function () {
  console.log('running 3000...')
})

module.exports = app

路由檔案

/**
 * router.js 路由模組
 * 職責:
 *   處理路由
 *   根據不同的請求方法+請求路徑設定具體的請求處理函式
 * 模組職責要單一,不要亂寫
 * 我們劃分模組的目的就是為了增強專案程式碼的可維護性
 * 提升開發效率
 */

var fs = require('fs')
var Student = require('./student')

// Express 提供了一種更好的方式
// 專門用來包裝路由的
var express = require('express')

// 1. 建立一個路由容器
var router = express.Router()

// 2. 把路由都掛載到 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) {
  // 1. 獲取表單資料
  // 2. 處理
  //    將資料儲存到 db.json 檔案中用以持久化
  // 3. 傳送響應
  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) {
  // 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
    })
  })
})

/*
 * 處理編輯學生
 */
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')
  })
})

/*
 * 處理刪除學生
 */
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')
  })
})



資料處理檔案 student.js

/**
 * student.js
 * 資料操作檔案模組
 * 職責:操作檔案中的資料,只處理資料,不關心業務
 *
 * 這裡才是我們學習 Node 的精華部分:奧義之所在
 * 封裝非同步 API
 */

var fs = require('fs')

var dbPath = './db.json'

/**
 * 獲取學生列表
 * @param  {Function} callback 回撥函式
 */
exports.find = function (callback) {
  fs.readFile(dbPath, 'utf8', function (err, data) {
    if (err) {
      return callback(err)
    }
    callback(null, JSON.parse(data).students)
  })
}

/**
 * 根據 id 獲取學生資訊物件
 * @param  {Number}   id       學生 id
 * @param  {Function} callback 回撥函式
 */
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)
  })
}

/**
 * 新增儲存學生
 * @param  {Object}   student  學生物件
 * @param  {Function} callback 回撥函式
 */
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)
    })
  })
}

/**
 * 更新學生
 */
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
    })

    // 這種方式你就寫死了,有 100 個難道就寫 100 次嗎?
    // 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)
    })
  })
}

/**
 * 刪除學生
 */
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)
    })
  })
}