1. 程式人生 > 實用技巧 >Node.js框架--Express

Node.js框架--Express

Express 的特點:

  • 易上手

  • 高效能

  • 擴充套件性強:可以自由的拆分和安裝模組

安裝 Express

// 示例:使用 express 快速搭建一個伺服器

const express = require('express');
const app = express();

app.get('/', (req, res)=>{
    res.send('<h1>Hello Express</h1>')
}).listen(3000,()=>{
    console.log('伺服器已經啟動...');
})

Express 本質是一個非常簡潔的框架,這個框架本身只是由中介軟體

路由組成。

中介軟體

本身正常的過程是傳送請求到伺服器,伺服器端對請求進行處理,然後給客戶端響應。中介軟體就是在接收到前端的請求後,做出的一系列的工作。

// 下面是一箇中間件的示例

function 中介軟體的名字(req, res, next){
  // req 代表 http 請求
  // res 代表 http 響應
  // next 呼叫下一個中介軟體
}

app.use(中介軟體的名字); //註冊中介軟體

中介軟體的使用(註冊:use)的順序是很重要的。後面我們在使用中介軟體的時候,一定要注意中介軟體的前後順序關係。

一般來講,我們不會涉及到自己書寫中介軟體,一般都是使用第三方的中介軟體。

下面以 body-parser 中介軟體為例

安裝 body-parser

npm i body-parser

  具體方法

// 示例:使用 express 快速搭建一個伺服器

const express = require('express');
const app = express();
const bodyParser = require('body-parser'); // 引入第三方中介軟體

// 註冊中介軟體
// 這邊註冊 bodyParser 的時候,設定一下解析規則
// 原生的 node,如果要獲取 post 請求的資料,需要監聽事件
// data,end,bodyParser 就可以讓我們很輕鬆的獲取到 post 請求的資料
app.use(bodyParser.urlencoded({extended : false}));
app.use(bodyParser.json()); // 把資料解析成 json 物件

let str = `
    <form method="POST" action="">
        <div>
            name : <input type="text" name="username">
        </div>
        <div>
            age : <input type="text" name="userage">
        </div>
        <button>提交</button>
    </form>
`

app.use('/', (req, res)=>{
    if(req.body.username && req.body.userage){
        console.log('拿到了客戶端post 請求的資料');
        console.log(`資料為:${req.body.username},${req.body.userage}`);
        res.send(`name 為${req.body.username},age 為${req.body.userage}`);
    } else {
        res.send(str);
    }
}).listen(3000,()=>{
    console.log('伺服器已經啟動...');
})

  

路由

所謂路由,就是對客戶端的請求進行合適的導航。

從 express 4.0 開始,路由已經成為了一個單獨的中介軟體,並且這個中介軟體是 express 內建。

// index.js
// 示例:使用 express 快速搭建一個伺服器

const express = require('express');
const app = express();
const router = require('./router');
// 所以我們需要設定路由將使用者不同的 url 導航到不同的頁面

app.use('/', router);

app.listen(3000,()=>{
    console.log('伺服器已經啟動...');
})

// router.js
// 這個就是我的路由檔案
// 專門用來管理應用程式的路由

const express = require('express');
const router = express.Router();

// 之後所有的路由配置都掛在這個 router 上面
router.get('/',(req,res)=>{
    res.send('這是首頁');
})

router.get('/contact',(req,res)=>{
    res.send('這是聯絡我們');
})

router.get('/detail',(req,res)=>{
    res.send('這是商品詳情');
})

module.exports = router;

  

靜態資源的託管

什麼是靜態資源?

所謂靜態資源,就是指 html,css,圖片,圖示,字型,這些都是靜態資源。

在 express 中內建了一箇中間件,專門用來管理靜態資源。

app.use(express.static(靜態資源的目錄));

  

__dirname:當前所在的目錄
__filename:當前檔案所在位置

例如:

console.log(__dirname); // /Users/Jie/Desktop/demo
console.log(__filename); // /Users/Jie/Desktop/demo/index.js

  接下來,我們來設定該專案的靜態資源目錄,程式碼如下:

// 示例:使用 express 快速搭建一個伺服器

const express = require('express');
const app = express();
const router = require('./router');
// 所以我們需要設定路由將使用者不同的 url 導航到不同的頁面

app.use(express.static(__dirname + '/public'))

app.use('/', router);

app.listen(3000,()=>{
    console.log('伺服器已經啟動...');
})

備註:此時在我們的專案根目錄下面新建一個 public 目錄,新建一個index.html,那麼express 會自動訪問到 index.html

express 腳手架

大家一聽到腳手架,第一反應就是工地上的腳手架,就是那個東西。腳手架和工地上的腳手架其實是一個意思,就是把專案的架子搭建起來。

首先第一步,需要安裝腳手架工具:

npm i express-generator -g

安裝完成後,我們就可以使用命令:

express <專案名>

但是搭建起來的專案,沒有依賴項,所以需要 npm i 安裝依賴。

安裝完成之後,npm start 就可以啟動了。

搭建好專案之後,接下來我們來看一下整個專案的目錄結構。

  • app.js:入口檔案

  • bin:二進位制目錄

  • node_modules:依賴包

  • package.json:依賴包的記錄檔案

  • public:靜態目錄

  • routes:路由

  • views:頁面模板

接下來,我們要來做一個具體的專案:學生管理系統

首先,我們的專案已經用 express 腳手架搭建起來了,我們也學過 mongodb

接下來我們就要把兩者結合起來,研究一下 express 搭建的專案中如何訪問mongodb

mongoose

mongoose 是一個 node.js 操作 mongodb 的驅動程式

所謂驅動程式,就是提供了一套介面。比如,我們新買了一個滑鼠,滑鼠和我的電腦系統實際上是各自獨立,現在,我想用我的作業系統去操作滑鼠,那就需要有一套介面程式,我的作業系統,只需要去呼叫這一套介面,就可以操作滑鼠,那麼,這一套介面就是驅動程式。

nodejs 和 mongodb 也是兩個獨立的東西。要想 nodejs 去操作mongodb,我們就需要安裝相應的驅動程式才行。

首先第一步,安裝 mongoose

npm i mongoose

接下來,我們來看一下 mongoose 的使用步驟:

  • 建立資料模型

  • 在資料模型的基礎上呼叫各種方法來操作 mongodb 資料庫

接下來,我們 來一步一步的做,首先第一步,建立一個 db.js ,該檔案負責連線資料庫,程式碼如下:

// 該檔案負責書寫連線資料庫的相關配置

const mongoose = require('mongoose');
// 連線資料庫的字串,說明要連線 f71 資料庫
const dbURI = 'mongodb://localhost/f71'; 

mongoose.connect(dbURI,{useNewUrlParser : true, useUnifiedTopology : true});

mongoose.connection.on('connected',()=>{
    console.log('資料庫已經連線...');
})

  接下來,我們就需要建立資料模型,在專案根目錄程式碼建立一個 stuModel 的檔案,這個檔案就是學生模型,程式碼如下:

// 該檔案就是資料模型檔案
require('./db.js')
const mongoose = require('mongoose');

// 1. 建立 Schema,Schema 就是我們資料模型的骨架
// 在建立 Schema,就需要和集合(表)進行對應
const stuSchema = new mongoose.Schema({
    name : String,
    age : Number,
    gender : String,
    score : Number
});

// 2. 根據上面建立的 Schema 來生成資料模型
// (1) model 的名字 (2)定義的 Schema (3)和資料庫的哪個集合關聯
mongoose.model('stuModel',stuSchema,'stu');

// 3. 將這個模型匯出去,後面所有的操作(增刪改查)都是基於這個模型
module.exports = mongoose.model('stuModel');

  

接下來,既然我們的模型已經建立好了,接下來我們就要開始使用這個模型來看一下是否能操作 mongodb 資料庫

具體程式碼如下:

const stuModel = require('./stuModel');

stuModel.find((err, data)=>{
    console.log(data);
})

  

三層架構

什麼是三層架構?

最早是來自於微軟的後端分層的思想。以前的 web 開發是重伺服器端,輕客戶端。

補充:高類聚,低耦合

所謂高類聚,就是封裝一個模組,這個模組應該儘量關心自己的功能。

所謂耦合,就是模組與模組之間的關係,低耦合,就是模組與模組之間的關係要儘量的低。

一般來講,封裝一個模組,如果該模組高類聚,那麼它必然也是低耦合。

三層架構的解釋如下:

三層架構就是為了符合“高內聚,低耦合”思想,把各個功能模組劃分為表示層(UI)、業務邏輯層(BLL)和資料訪問層(DAL)三層架構,各層之間採用介面相互訪問,並通過物件模型的實體類(Model)作為資料傳遞的載體,不同的物件模型的實體類一般對應於資料庫的不同表,實體類的屬性與資料庫表的欄位名一致。 [1]

三層架構區分層次的目的是為了 “高內聚,低耦合”。開發人員分工更明確,將精力更專注於應用系統核心業務邏輯的分析、設計和開發,加快專案的進度,提高了開發效率,有利於專案的更新和維護工作。

接下來,我們來看一下在我們的專案中,如何實現三層架構。

首先在專案根目錄下,建立 dao 和 service 目錄,dao 就是持久層,service 就是業務層,routes 就作為我們的表現層。

dao 既然作為持久層,所以,我們所有的資料庫相關的操作,都應該放進dao目錄裡面。

在 dao 層裡面新建 model 目錄,所有的 model 放進這個目錄裡面。db.js 也放進這個 dao 目錄。

stuDao.js 負責和資料庫打交道,具體程式碼如下:

const stuModel = require('./model/stuModel');

module.exports.getStuDao = async function(){
    return await stuModel.find();
}

  dao 層操作資料庫拿到的資料傳遞給業務層,程式碼如下:

// 這一層就是我們的業務層

const {getStuDao} = require('../dao/stuDao');

module.exports.getStuService = async function(){
    return await getStuDao()
}

  業務層的程式碼又會傳遞給表現層,程式碼如下:

var express = require('express');
var router = express.Router();
// 引入業務層的方法
const {getStuService} = require('../service/stuService');

/* GET home page. */
router.get('/stu', async function(req, res, next) {
  res.send(await getStuService());
});

module.exports = router;

  

Restful

在解釋 restful 之前,我們先來看一下 rest。

rest 的英語全稱為 Representational State Transfer,翻譯成中文是“表現層狀態轉移”。

其實這句話完整的說法是 resource representational state transfer,資源在表現層的狀態轉移。

  • 資源:指的就是網路資源,或者說網路資料。網路上的一切東西都可以稱之為資源,例如一首歌,一部電影,一張圖片,一個圖示。網路上有這麼多資源,我們使用 URI 來標記。所謂上網,其實就是資源之間的互動。

  • representational state:表現層,指的是資源的一種表現形式。一段資料,我可與使用 json 來表示,也可以使用 xml 來表示。上面提到的 URI 只代表存在這個資源,但是這個資源的表現形式由表現層來定義。當我們請求一個數據的時候,響應頭裡面有一個欄位 content-type:html/text png/image jpeg/image

  • transfer:資源存續的狀態轉移。前面在學習 http 協議的時候,有 GET 請求、POST 請求,這些請求方式其實就是對一個資源進行操作

Restful 其實核心就是一點,應該使用不同的 HTTP 請求方式來標記資源狀態的改變。

HTTP 請求方式,實際上是有很多的:

  • GET

  • POST

  • DELETE

  • PUT

  • PATCH

  • ....

使用 restful 設計 URL 前後的對比。

刪除一個評論:http://abc.com/?method=comment.del&id=xxx

或者

http://abc.com/comment/del/xxx

這樣設計 API 違背了 URI 的本質,URI 本質僅僅是標記網際網路上面的一個資源,不應該參雜任何的對該資源做出處理的行為

通過 Restful 的 URI 設計風格,可以還原 URI 的本質,讓 URI 僅僅是表示一個資源而已。

任何對該資源做的操作,都應該通過 HTTP 的請求方式來表示:

http://abc.com/comment/1