这篇主要是实现路由注解,用过nestjs的都知道,其路由都是通过注解来实现的,如有控制器@Controller(),@Get()...等等,nestjs 底层框架可选 是expres或者是Fastify,在这里我选择 koa2。
话不多说,直接上代码
src/koa-decorator.ts
引入相关库
- import "reflect-metadata";
- import path from "path";
复制代码 类型声明
- /******** 类型声明********* */
- export type IMethondType = "get" | "post" | "delete" | "put" | "all";
- export type IRouterType = {
- path: string | RegExp;
- methond: string | IMethondType;
- };
- //一个方法对应一个路由信息
- export type IKeyMapRouters = {
- [methondName: string]: IRouterType;
- };
- // 类的元数据参数
- export type IControllerMetate = {
- prefix: string | undefined;
- routers: IKeyMapRouters;
- };
复制代码 常量声明
- /********常量声明********* */
- export const CONTROLLER_META_KEY = Symbol("controller_meta_key"); // 控制器类装饰器key
- export const MOTHOD_META_KEY = Symbol("method_meta_key"); // 类方法装饰器key
- export const PARAMS_META_KEY = Symbol("params_meta_key"); // // 类方法参数装饰器key
- export const DesignParamtypes = "design:paramtypes"; //内置的获取构造函数的参数
复制代码 类控制装饰器
- /*********类控制装饰器************** */
- export function Controller(prefix?: string) {
- return function (target: Object) {
- let meta: IControllerMetate = getControllerMeta(target);
- meta.prefix = prefix;
- Reflect.defineMetadata(CONTROLLER_META_KEY, meta, target);
- };
- }
- // 获取类元数据参数
- export function getControllerMeta(target: Object) {
- let classMeta: IControllerMetate = Reflect.getMetadata(
- CONTROLLER_META_KEY,
- target
- );
- if (!classMeta) {
- classMeta = { prefix: "", routers: {} };
- Reflect.defineMetadata(CONTROLLER_META_KEY, classMeta, target);
- }
- return classMeta;
- }
复制代码 类方法装饰器
- /***************类方法装饰器************************ */
- // 方法
- export function RequestFactory(methond: string) {
- return function (path?: string) {
- return function (target: any, methodName: string, dec: PropertyDescriptor) {
- let classMeta: IControllerMetate = getControllerMeta(target);
- let methondMeta: IRouterType = { path: path || "", methond };
- classMeta.routers[methodName] = methondMeta;
- Reflect.defineMetadata(
- CONTROLLER_META_KEY,
- classMeta,
- target.constructor
- );
- };
- };
- }
- export const GET = RequestFactory("get");
- export const POST = RequestFactory("post");
- export const PUT = RequestFactory("put");
- export const DELETE = RequestFactory("delete");
- export const ALL = RequestFactory("all");
复制代码 类方法参数装饰器
- /**********类方法参数装饰器*********************** */
- // 方法参数
- export function factroyParameter(fn: Function) {
- return function (target: any, methodName: string, paramsIndex: number) {
- let meta: Array<Function> =
- Reflect.getMetadata(PARAMS_META_KEY, target, methodName) || [];
- meta.unshift(fn);
- Reflect.defineMetadata(PARAMS_META_KEY, meta, target, methodName);
- };
- }
- // 上下文装饰器
- export function Ctx<T = any>() {
- return factroyParameter((ctx: T) => ctx);
- }
- //请求
- export function Req<T extends { request: any }>() {
- return factroyParameter((ctx: T) => ctx.request);
- }
- // 响应
- export function Res<T extends { response: any }>() {
- return factroyParameter((ctx: T) => ctx.response);
- }
- // url 的参数
- export function Query<T extends { request: Record }>(field?: any) {
- return factroyParameter((ctx: T) =>
- field ? ctx.request.query[field] : { ...ctx.request.query }
- );
- }
- // url 动态参数
- export function Param<T extends { request: any }>() {
- return factroyParameter((ctx: T) => ctx.request.param);
- }
- //请求体参数
- export function Body<T extends { request: any }>() {
- return factroyParameter((ctx: T) => ctx.request.body);
- }
- // 请求头
- export function Header<T extends { request: Record }>(field?: any) {
- return factroyParameter((ctx: T) =>
- field ? ctx.request.headers[field] : ctx.request.headers
- );
- }
- // next 方法
- export function Next<T extends Function>() {
- return factroyParameter((_: any, next: T) => next);
- }
复制代码 注册类控制器的路由(核心方法)
- /**
- * 注册类控制器的路由
- */
- export function ResigerRouter(
- routerIntance: any,
- controllerInstance: Object | Function
- ) {
- if (!routerIntance) {
- throw `路由实例不能为空`;
- }
- if (typeof controllerInstance == "function") {
- controllerInstance = Reflect.construct(controllerInstance, []);
- }
- if (
- typeof controllerInstance == "object" &&
- typeof controllerInstance.constructor != "function"
- ) {
- throw `控制器不是一个类函数,注册失败`;
- }
- let { prefix, routers }: IControllerMetate = getControllerMeta(
- controllerInstance.constructor
- );
- for (let key in routers) {
- if (key == "constructor") return;
- let routerMeat = routers[key];
- let pathname;
- if (routerMeat.path instanceof RegExp) {
- pathname = routerMeat.path;
- } else if (typeof routerMeat.path !== "object") {
- pathname =
- path
- .join("/", prefix || "", routerMeat.path || "")
- .replace(/\\+/g, "/") || "/";
- }
- //方法参数
- let parameterMeta =
- Reflect.getMetadata(PARAMS_META_KEY, controllerInstance, key) || [];
- let actionFn = async (ctx: any, next: Function) => {
- let args = parameterMeta.map((item: Function) =>
- item(ctx, next, controllerInstance, key)
- );
- const resBody = await (controllerInstance as any)[key].call(
- controllerInstance,
- ...args
- );
- if (resBody !== undefined) ctx.body = await resBody;
- await next();
- };
- let methond = routerMeat.methond;
- routerIntance[methond](pathname, actionFn);
- }
- }
复制代码 测试用例
- import koaRouter from "koa-router";
- import Koa from "koa";
- import { Controller, Ctx, GET, Query, ResigerRouter } from "./koa-decorator";
- const app = new Koa();
- let rotuer = new koaRouter({
- prefix: "/api",
- });
- @Controller("user")
- class User {
- @GET("list")
- getUserId(@Query("id") id: string, @Ctx() ctx: Koa.DefaultContext): string {
- console.log("ctx", ctx);
- return this.computed(id);
- }
- computed(value: string): string {
- return value + "---computed";
- }
- }
- // 加载路由
- ResigerRouter(rotuer, User);
- app.use(rotuer.routes());
- app.listen(8080, () => {
- console.log("server is run in prot 8080");
- });
- // 访问:http://127.0.0.1:8080/api/user/list?id=1
复制代码 总结
1、这是使用koa ,koa-router 为底层,无破坏,无侵入实现的路由装饰器的框架
2、支持可以扩展更多的其他功能的装饰器
3、此路由框架与上以一篇的实现的ioc框架之前是没有关联的,目前两个都是单独无耦合的
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |