ts + reflect 编程, 实现 类 spring bo

2021-11-06  本文已影响0人  ithankzc

目的

用 ts + reflect-metadata 实现 spring boot rest注解。

在 java 和 spring boot 项目,随处可见注解,给大家看一段代码

@RequestMapping("/accounts")
class AccountController {

    @GetMapping("/info")
    getId(ctx) {
        ctx.body = {
            "id": 10086,
        };
    }
}

熟悉 java 的人 会看着好眼熟, 但其实这是 js 的代码。 结合 ts,reflect-metadata, 我们可以写出类似 java 注解 的代码及实现功能。

工具类方法

const METHOD_METADATA = 'method';
const PATH_METADATA = 'path';

const createMappingDecorator = (method: string) => (path: string): MethodDecorator => {
    return (target, key, descriptor) => {
        Reflect.defineMetadata(PATH_METADATA, path, descriptor.value);
        Reflect.defineMetadata(METHOD_METADATA, method, descriptor.value);
    }
}

const GetMapping = createMappingDecorator('GET');

function RequestMapping(path: string): ClassDecorator {
    return target => {
        Reflect.defineMetadata(PATH_METADATA, path, target);
    }
}

function mapRoute(instance: Object) {
    const prototype = Object.getPrototypeOf(instance);

    // 筛选出类的 methodName
    const methodsNames = Object.getOwnPropertyNames(prototype)
        .filter(item => <any>_.isFunction(prototype[item]) && item != "constructor");
    return methodsNames.map(methodName => {
        const fn = prototype[methodName];

        // 取出定义的 metadata
        const path = Reflect.getMetadata(PATH_METADATA, fn);
        const method = Reflect.getMetadata(METHOD_METADATA, fn);
        return {
            path,
            method,
            fn,
            methodName
        }
    })
}

结合 koa, koa-router 实现的 rest 请求

const Koa = require('koa');
const Router = require('@koa/router');
const app = new Koa();
let router = new Router();

let requestPrefix = Reflect.getMetadata(PATH_METADATA, AccountController);
let routeInfo = mapRoute(new AccountController());
routeInfo.forEach((item) => {
        router[item.method.toLowerCase()](item.path, item.fn);
    }
);
router.prefix(requestPrefix);

app.use(router.routes()).use(router.allowedMethods());
app.listen(3000, () => {
    console.log("listen 3000")
});

参考文档:

https://github.com/koajs/router/blob/HEAD/API.md#module_koa-router
https://github.com/rbuckton/reflect-metadata
https://jkchao.github.io/typescript-book-chinese/tips/metadata.html#controller-%E4%B8%8E-get-%E7%9A%84%E5%AE%9E%E7%8E%B0

上一篇下一篇

猜你喜欢

热点阅读