1. 程式人生 > 程式設計 >koa使用裝飾器動態建立路由(router)

koa使用裝飾器動態建立路由(router)

前言

在node專案,不管是koa/express路由的使用中,我們建立路由一般都是這樣的姿勢

router.post("/api/test",middleware,handler); // 建立路由
複製程式碼

比如:

router.jpg

我們一般建立路由的handler會單獨抽到其它檔案也就是所說的controller,這樣就會多了一步編寫router的過程。那麼這一步是否可以省略呢?

當然可以,本文帶你一步步使用裝飾器統一處理構建路由,這樣不用在寫完某一個controller的方法後再進行建立router啦,使用裝飾器,我們只需要在某一個介面方法上新增路由的裝飾就可以進行建立router。那麼精彩來啦~

專案結構

專案結構.jpg

開始啦,一步步教你使用裝飾器構建路由嘍!

初始化專案

初始化package.json

新建一個目錄,用vscode開啟。執行npm init初始化建立package.json

安裝koa專案使用的第三方包:

npm install -S koa koa-router koa-bodyparser koa-compress

  • koa-router 管理路由
  • koa-bodyparser 讀取post,put資料轉化物件格式
  • koa-compress 壓縮請求資料提高傳輸速度

配置babel支援ES6 ES7

因為專案使用裝飾器配置路由,必須支援ES7語法,才需要配置babel

本文配置的是babel7版本

下面我帶大家一步步配置babel

npm install -D @babel/core 
npm install -D @babel/preset-env
npm install -D @babel/plugin-proposal-decorators
npm install -D @babel/register
複製程式碼

babel7版本 使用的是@babel,7以下是babel-xxx 這點很容易區分

下面介紹一下這些包的功能

  • @babel/core babel 核心程式碼
  • @babel/preset-env 編譯新版的語法 如:箭頭函式,但是並不轉換新版api 如:Array.include 轉換新版api及相容瀏覽器之間的差異(相容ie)需要 babel-polyfill
  • @babel/plugin-proposal-decorators 解析裝飾器
  • @babel/register 在執行時進行即時編譯,不是進行先編譯在執行

然後在專案根目錄建立.babelrc檔案

配置預設,外掛

{
  "presets": [
    ["@babel/preset-env",{
      "targets": {
        "node": "current"
      }
    }]
  ],"plugins": [
    ["@babel/plugin-proposal-decorators",{ "legacy": true }]
  ]
}
複製程式碼

到此,配置結束。專案比較簡單,這些babel配置在本專案已經足夠使用,接下來就可以愉快的使用es6,裝飾器新語法了

建立node服務

新建index.js,app.js啟動一個服務

index.js 主要是進行babel註冊,以及啟動服務的中介檔案。 為什麼會這樣呢?在這個檔案進行使用動態編譯,但是編譯的時候是不會編譯index.js檔案的,所以,這個檔案還是需要使用e5的舊語法

require("@babel/register")
require("./app")
複製程式碼

app.js才會去真正啟動node服務

import Koa from "koa"
import bodyparser from "koa-bodyparser"
import compress from "koa-compress"

app.use(compress());
app.use(bodyparser());


const PORT = 8081;
app.listen(PORT,()=>{
    console.log(`啟動成功! env=${process.env.NODE_ENV}`)
    console.log(`Listening at http://localhost:${PORT}`)
})
複製程式碼

配置執行命令,啟動服務

然後需要新增package.json的執行命令

"dev":"cross-env NODE_ENV=development nodemon ./index.js"

這裡用到了兩個node開發中常用的兩個外掛cross-envnodemon其主要用途如下

安裝npm install -D cross-env nodemon,安裝到devDependencies

  • cross-env 給專案新增環境變數區分是開發環境和生產環境,一般在執行npm命令前新增環境變數通過

這個地方添加了NODE_ENV變數,在程式中可以通過process.env.NODE_ENV獲取執行命令新增的變數值

  • nodemon 可以替代node啟動服務,只是nodemon功能豐富,可以監聽程式碼的更改重新啟動專案

下面執行npm run dev可以看到服務啟動成功

1565227107(1).jpg

新增路由裝飾器

在專案根目錄新建common目錄,然後在common目錄下新建decorator目錄,在這個目錄新建index.js

no bi bi ,上程式碼:

/**
 * 請求方法
 */
export const RequestMethod = {
    "GET":"get","POST": "post","PUT": "pust","DELETE": "delete","OPTION": "option","PATCH": "patch"
}

/**
 * 定義註冊的路由陣列
 */
export const controllers = [];

/**
 * 給controller新增裝飾
 * @param {*} path 
 */
export function Controller(path=""){
    return function(target){
        // 給controller類新增路由字首
        console.log(target)
        target.prefix = path;
    }
}

/**
 * 給controller類的方法新增裝飾
 * url 可選
 * method 請求方法
 * middleware 中介軟體
 */
export function RequestMapping({url="",method="",middleware=[]}){
    return function(target,name,descriptor){
        let path = "";
        // 判斷有沒有定義url
        if(!url){
            // 取方法名作為路徑
            path = `/${name}`;
        }else{
            // 自己定義的url
            path = url;
        }
        // 建立router需要的資料 url,method,middleware(可以沒有),最終執行的方法,裝飾器隊物件的建構函式
        const item = {
            url:path,method:method,middleware:middleware,handler:target[name],constructor:target.constructor,};
        controllers.push(item);
    }
}
複製程式碼

路由的統一建立

建立router資料夾,再繼續建立index.js檔案

no bi bi ,上程式碼:

此檔案是統一建立路由的入口檔案,需要傳入koa例項和koa-router例項進行建立路由和路由裝箱

import { controllers } from "./../common/decorator"
/**
 * 初始化路由
 */
export default (app,router) => {
    controllers.forEach((item) => {
        // 獲取每個路由的字首
        const prefix = item.constructor.prefix; 
        let url = item.url;
        if(prefix) url = `${prefix}${url}`; // 組合真正連結
        console.log(item.method,url); // 列印請求的路由method,url
        router[item.method](url,...item.middleware,item.handler); // 建立路由
    });
    app.use(router.routes()).use(router.allowedMethods()) // 路由裝箱
}
複製程式碼

然後在 app.js進行初始化路由:

initRoutes(app,router)
複製程式碼

使用

建立controler/index.js,middleware/index.js

middleware/index.js的測試程式碼

export default async (ctx,next)=>{
    console.log("middleware")
    await next();
}
複製程式碼

controler/index.js的測試程式碼:




import {RequestMethod,Controller,RequestMapping } from "./../common/decorator/index"
import TestFun from './../middleware/index'

// 新增Controller字首
@Controller("/api/test")
export default class TestController {

    // 基本面使用 /api/test/login
    @RequestMapping({
        url:"/login",method:RequestMethod.GET,// 定義請求方法
    })
    async login(ctx){
        ctx.body = {
            code:0,message:"success"
        }
    }

    // 定義有中介軟體的router  /api/test/test
    @RequestMapping({
        method:RequestMethod.POST,// 定義請求方法
        middleware: [TestFun] // 使用中介軟體
    })
    async test(ctx){
        ctx.body = {
            code:0,message:"success"
        }
    }

    
}
複製程式碼

把conttroller/index.js 在 router/index.js匯入並匯出 export * from "../controller/index" 如果還有其它controller,那麼只需要在router/index.js新增就可以了~

重啟服務

1565241373(1).jpg

使用postman測試

1565240592(1).jpg

1565240617(1).jpg

ok,搞定~,以後再也不用寫router啦,感覺爽了很多!

程式碼註釋很詳細,若有什麼不理解或者更好的建議,歡迎各位同學留言交流

我的簡書主頁