node路由两种注入方式(约定式/装饰器)
1. 约定式
text// 通过约定式文件路径设置,自动注册路由 const routerDir = path.resolve(__dirname, "../router"); const routes = fs.readdirSync(routerDir); routes.forEach((route) => { const routeitem = require(path.resolve(routerDir, route)); app.use(routeitem.routes()).use(routeitem.allowedMethods()); });
2. 借助ts装饰器
原始方式的实现
textconst articleRouter = new Router({ prefix: "/article" }); // 插入一篇文章 articleRouter.post( "/", verifyAuth, upload.any(), datalize([ filed("title").required(), filed("content_md").required(), filed("category_id").required(), filed("tag_id").required(), ]), datalizeError, checkCategory, checkTag, saveCover, add ); // 更改文章封面 articleRouter.post( "/cover/:article_id", verifyAuth, upload.any(), datalize([filed("cover")]), datalizeError, checkCover, deleteOldCover, changeCoverById );
装饰器实现
text// 使用 // @prefix("/evaluate") // @get("/:ISBN") // @post("/:ISBN") // @use(verfyAuth) import { Context } from "koa"; import prefix from "../Decorator/prefixDecorator"; import { get, post } from "../Decorator/methodDecorator"; import bookServer from "../service/book"; import { success } from "../common/ResResult"; import evaluateServer from "../service/evaluate"; import use from "../Decorator/useDecorator"; import { verfyAuth } from "../middleware/user"; @prefix("/evaluate") class EvaluateController { @get("/:ISBN") async findAllEvaluateByISBN(ctx: Context) { const { ISBN } = ctx.params; const result = await evaluateServer.getEvaluateReplyList(ISBN); ctx.body = success(result); } @use(verfyAuth) @post("/:ISBN") async addEvaluateBook(ctx: Context) { const { ISBN } = ctx.params; const { content, evaluator, evaluatedegree } = ctx.request.body; const result = await evaluateServer.addEvaluateBook( ISBN, content, evaluator, ctx.user.userid, evaluatedegree ); ctx.body = success(result); } @use(verfyAuth) @post("/reply/:evaluateid") async applyInfo(ctx: Context) { const { evaluateid } = ctx.params; const { content, replyor } = ctx.request.body; const result = await evaluateServer.applyInfo(evaluateid, content, replyor); ctx.body = success(result); } } // 实现 // @prefix("/evaluate") import Router from "koa-router"; import type { IRequestType } from "./type"; import rootRouter from "../config/rootRouter"; import { Middleware } from "koa"; function prefix(prefix: string) { return function (target: new (...args: any[]) => any) { const router = new Router({ prefix }); // 遍历类中所有的方法 => defineMeta时保存的key for (let fn in target.prototype) { // 获取路径和方法 const path = Reflect.getMetadata("path", target.prototype, fn); const type: IRequestType = Reflect.getMetadata( "type", target.prototype, fn ); const middlewareArr: Middleware[] = Reflect.getMetadata( "middleware", target.prototype, fn ); if (middlewareArr) { router[type](path, ...middlewareArr, target.prototype[fn]); } else { router[type](path, target.prototype[fn]); } // router上添加路由 } // 载入rootRouter rootRouter.use(router.routes(), router.allowedMethods()); }; } export default prefix; // @get("/:ISBN") // @post("/:ISBN") import { IRequestType } from "./type"; function getMethodDecorator(type: IRequestType) { return function (path: string) { return function (target: any, key: string, desc: PropertyDescriptor) { // 元信息保存路径名 Reflect.defineMetadata("path", path, target, key); // 元信息保存方法名 Reflect.defineMetadata("type", type, target, key); }; }; } const get = getMethodDecorator(IRequestType.GET); const post = getMethodDecorator(IRequestType.POST); const del = getMethodDecorator(IRequestType.DEL); const put = getMethodDecorator(IRequestType.PUT); export { get, post, del, put }; // @use(verfyAuth) import { Middleware } from "koa"; function use(middleware: Middleware) { return function (target: any, key: string) { // 先获取中间件 let mw: Middleware[] = Reflect.getMetadata("middleware", target, key); if (!mw) { // 没有中间件 mw = [middleware]; } else { mw.push(middleware); } // 定义中间件 Reflect.defineMetadata("middleware", mw, target, key); }; } export default use;