基于 Koa与Decorator改个Spring Boot轮子

481 阅读1分钟

在考究了nodejs以及nestjs后,觉得nestjs用的不是特别爽,于是开始不自量力的写起了这个框架玩,希望能在造轮子的过程中学到更多有趣的东西。

nestjs基于express,我的quick-d基于koa,目前只是雏形阶段,还在慢慢搭建与完善。

牢记非侵入式设计!!!

牢记非侵入式设计!!!

牢记非侵入式设计!!!

github 项目地址

目录

一、控制层装饰器(@Controller)

二、路由装饰器(@Request,@Get、Post、Put、DeleteRequest)

三、参数装饰器(@BodyParam,@Query)

四、全局错误处理 异常解决方案

五、自动装载与容器管理

核心技术

装饰器、反射

一、控制层装饰器

common/Controller.js 文件中

const Controller = (path: string = ''): ClassDecorator => {
  return (originClass: Function) => {
    if (global['$Quick-D'] === undefined) {
      // 这里相当于定义一个容器运行环境在全局
      global['$Quick-D'] = {}
      global['$Quick-D']['controllers'] = {}
    }
    // 将这个添加了该装饰器的对象加到容器中管理
    global['$Quick-D']['controllers'][originClass.name] = originClass

    // 将装饰器函数获取的参数通过反射机制加到原型链上
    Reflect.defineMetadata('path', path, originClass)
    Reflect.defineMetadata('router', new Router(), originClass)
  }
}

二、路由装饰器

三、参数装饰器

四、全局错误处理 异常解决方案

五、自动装载与容器管理

index.js 文件中

/**
 * 接收主程序传来的 APP 实体
 */
let APP = undefined

/**
 * 反射获取controller中的数据
 * @param controller  路由控制层对象
 * @returns {{path: any, routes: any, router: any}}
 */
const reflectGetData = controller => {
  return {
    path    : Reflect.getMetadata('path',   controller),
    router  : Reflect.getMetadata('router', controller),
    routes  : Reflect.getMetadata('routes', controller)
  }
}

/**
 * 为框架注册 koa应用实体
 * @param app koa应用实体
 */
const registerApp = (app: Koa) => {
  APP = app
  APP.use(koaBodyparser())

  const oldListen = APP.listen
  APP.listen = (...args) => {
    const controllers = global['$Quick-D']['controllers']
    for (const controllerName in controllers) {
      const controller = controllers[controllerName]
      const instance = new controller()

      const {
        path, router, routes
      } = reflectGetData(controller)
    }
  }
  oldListen.call(APP, ...args)
}

src/app.js 项目入口文件中

import Koa from 'koa'
import config from './config'
import { registerApp } from '~/lib/decorator/quick-d'

global.MAIN_APP = new Koa()

registerApp(MAIN_APP)

const controllersFileNames = require('fs').readdirSync(__dirname + '/controller')
for (let controllersNameIndex in controllersFileNames) {
  const controllersName = controllersFileNames[controllersNameIndex]

  if (/\.js$/.test(controllersName)) {
    require(`@/controller/${controllersName}`)
  }
}