koa使用裝飾器動態建立路由(router)
前言
在node專案,不管是koa/express路由的使用中,我們建立路由一般都是這樣的姿勢
router.post("/api/test",middleware,handler); // 建立路由
複製程式碼
比如:
我們一般建立路由的handler
會單獨抽到其它檔案也就是所說的controller
,這樣就會多了一步編寫router的過程。那麼這一步是否可以省略呢?
當然可以,本文帶你一步步使用裝飾器統一處理構建路由,這樣不用在寫完某一個controller
的方法後再進行建立router
啦,使用裝飾器,我們只需要在某一個介面方法上新增路由的裝飾就可以進行建立router。那麼精彩來啦~
專案結構
開始啦,一步步教你使用裝飾器構建路由嘍!
初始化專案
初始化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-env
,nodemon
其主要用途如下
安裝npm install -D cross-env nodemon
,安裝到devDependencies
- cross-env 給專案新增環境變數區分是開發環境和生產環境,一般在執行npm命令前新增環境變數通過
這個地方添加了NODE_ENV
變數,在程式中可以通過process.env.NODE_ENV
獲取執行命令新增的變數值
- nodemon 可以替代node啟動服務,只是nodemon功能豐富,可以監聽程式碼的更改重新啟動專案
下面執行npm run dev
可以看到服務啟動成功
新增路由裝飾器
在專案根目錄新建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新增就可以了~
重啟服務
使用postman測試
ok,搞定~,以後再也不用寫router啦,感覺爽了很多!
程式碼註釋很詳細,若有什麼不理解或者更好的建議,歡迎各位同學留言交流