《Nodejs實戰》筆記五:用Express實現留言版功能

3. Express

Express是在connect基礎上搭建的, 先安裝express的腳手架html

npm install -g express-generator

使用ejs模板引擎node

express -e express-project

3.1 留言版項目規劃

功能需求git

  1. 用戶能夠註冊,登陸,退出
  2. 用戶能夠發消息
  3. 訪問者能夠分頁瀏覽條目
  4. 有一個簡單的REST API

3.2 渲染視圖

Express幾乎支持全部的模板引擎,本項目使用ejsgithub

Express有兩種渲染視圖的方法:redis

  1. app.render() 在程序層使用
  2. res.render() 在請求或者響應層使用

本項目只會使用res.render()數據庫

3.2.1 瞭解渲染機制

主要介紹三方面express

  1. 調整視圖的查找
  2. 配置默認的模板引擎
  3. 啓用視圖緩存,減小文件I/O

首先是設置 views, 給程序指明渲染視圖的路徑npm

app.set('views', __dirname + '/views')

ps: __dirname表示當前文件的目錄api

而後指定渲染引擎緩存

app.set('view engine', 'ejs');

視圖緩存
視圖緩存view cache是默認開啓的,
若是不開視圖緩存, 每次渲染

rers.render('user', {name: 'zmj'})

都會從硬盤中讀取html

若是開啓的,讀取了一次html後,會緩存好,下次再讀取的時候直接讀取緩存,而不用再去磁盤上讀了

3.2.2 將數據傳給視圖

  1. res.render()
  2. res.locals
  3. app.locals

3.3 express路由入門

這一節要作留言版的兩個功能

  1. 用特定路由的中間件校驗用戶提交的內容
  2. 實現特定路由的校驗

爲了實現校驗,給這個程序加上消息提交的功能(用戶不提交消息,你咋校驗=。=)

3.3.1 消息提交功能

消息提交功能要完成如下幾點

  • 建立消息模型
  • 添加與消息相關的路由
  • 建立消息表單
  • 添加業務邏輯
3.3.2 建立消息模型

表示沒有接觸過redis,=。=,硬着頭皮來吧。

這裏使用到了redis,安裝指南
去github上下win10版本 https://github.com/MicrosoftA...
下載msi的

省事,會自動幫你配好服務和環境
在cmd中測試一下

redis-cli.exe -h 127.0.0.1 -p 6379 
設置鍵值對 set myKey abc
取出鍵值對 get myKey

這裏咱們安裝好了redis服務器後,再去項目裏安裝redis模塊

npm install --save redis

redis的文檔 readme
中文命令手冊命令
官網的api api

redis支持不少數據結構,基本常見的都支持這裏使用到了列表

建立models/entry.js

const redis = require('redis')
const db = redis.createClient()

class Entry {
    static getRange(from, to, cb) {
        db.lrange('entries', from, to, (err, items) => {
            if (err) return cb(err)
            let entries = []
            items.forEach((item) => {
                entries.push(JSON.parse(item))
            })
            cb(null, entries)
        })
    }
    
    constructor(obj) {
        // obj = {a: 1, b: 2, c: 3}
        // this[a] = 1, this[b] = 2, this[c] = 3
        for (let key in obj) {
            this[key] = obj[key]
        }
    }

    save(cb) {
        // 將消息轉化爲字符串,保存到Redis列表中
        const entryJSON = JSON.stringify(this)
        db.lpush('entries', entryJSON, (err) => {
            if (err) return cb(err)
            cb()
        })
    }
}

module.exports = Entry

lpush是redis像列表中插入數據的方法,第一個參數是鍵名,第二個是值,第三個是回調

lrange是查詢數據的方法,第一個參數是鍵名,第二和第三個是起始位置和結束位置,第四個是回調

3.3.3 添加與消息相關的路由

建立模板文件post.ejs

<form action="/post" method="post">
    <p>
        <input type="text" name="entry[title]" placeholder="Title" />
    </p>
    <p>
        <input type="text" name="entry[body]" placeholder="Body" />
    </p>
    <p>
        <input type="submit" value="Post">
    </p>
</form>

而後創建路由

app.get('/post', entries.form)
app.post('/post', entries.submit)

/* 下面是routes/entries文件 */
// GET '/post'
exports.form = (req, res, next) => {
    res.render('post', { title: 'post' });
}
  
// POST '/post'
exports.submit = (req, res, next) => {
    console.log(req.body.entry)
    res.redirect('/')
    // res.render('post', { title: 'post' });
}

還要注意的地方,得打開bodyParse解析

app.use(express.urlencoded({ extended: true }));

將消息存入數據庫中

exports.submit = (req, res, next) => {
    const data = req.body.entry
    const entry = new Entry({
        username: 'zmj',
        title: data.title,
        body: data.body
    })
    entry.save((err) => {
        if (err) return next(err)
        res.redirect('/')
    })
}

顯示全部消息

// GET '/list'
exports.list = (req, res, next) => {
    Entry.getRange(0, -1, (err, entries) => {
        console.log(entries)
        res.render('entries', { 
            title: 'msg list',
            entries: entries
        })
    })
}
3.3.4 校驗表單

提及校驗表單,你可能第一種想的方式是在這裏面完成

// POST '/post'
exports.submit = (req, res, next) => {
    const data = req.body.entry
    const entry = new Entry({
        username: 'zmj',
        title: data.title,
        body: data.body
    })
    entry.save((err) => {
        if (err) return next(err)
        res.redirect('/')
    })
}

這種方式擴展性很差,咱們使用特定的中間件來實現校驗, 咱們建立一箇中間件middleware/validate.js

const parseField = (field) => {
    // 將 entry[filed] 解析爲 ['entry', 'filed']
    return field.split(/\[|\]/g).filter((s) => s)
}

const getField = (req, field) => {
    // 這個騷操做,我醉了! 首先val = req.body, 而後val = val[entry], 而後val = entry.filed
    let val = req.body
    field.forEach((prop) => {
        val = val[prop]
    })
    return val
}

exports.required = (field) => {
    field = parseField(field)
    return (req, res, next) => {
        if (getField(req, field)) {
            next()
        } else {
            res.render('error,你必須輸入標題')
            res.redirect('back')
        }
    }
}

exports.lengthAbove = (field, len) => {
    field = parseField(field)
    return (req, res, next) => {
        if (getField(req, field).length > len) {
            next()
        } else {
            res.render(`error,你內容必須超過${len}個長度`)
            res.redirect('back')
        }
    }
}

這段代碼理解起來有難度,但這很方便咱們使用中間件,以及添加各類驗證方式

使用驗證表單的中間件

app.post('/post', validate.required('entry[title]'), validate.lengthAbove('entry[body]', 5), entries.submit)

咱們只須要,將表單字段傳過來便可驗證,是否是很方便,擴展性也至關好!

該節總結

這一段實現了留言版的功能,使用redis當數據庫

能夠留言,對留言進行了簡單的校驗

這一節作了三個路由

  • GET /post: 顯示消息表單
  • POST /post: 提交消息表單
  • GET /list: 獲取消息列表

總言之,學到了很多東西。不少東西都是書上沒寫須要本身去手動查資料的,像express的一些api,redis的使用等等

相關文章
相關標籤/搜索