美文网首页
ts + reflect 编程, 实现 类 spring bo

ts + reflect 编程, 实现 类 spring bo

作者: ithankzc | 来源:发表于2021-11-06 16:15 被阅读0次

    目的

    用 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

    相关文章

      网友评论

          本文标题:ts + reflect 编程, 实现 类 spring bo

          本文链接:https://www.haomeiwen.com/subject/hxchzltx.html