tornado项目之路由装饰器

当前项目为例进行拆分,代码

  1. 当我们进行启动项目的时候,首先需要的就是注册路由,所以我们可以定义一个方法,这个方法叫get_handlers,来获取整个项目的路由
  2. 但是如何表示一个类是一个路由呢?这个时候,我们就用到了装饰器open_handler,经过这个装饰器装饰的类,那么他就是一个路由,所以open_handler至少有两个参数
    1. path路径
    2. index用于路由排序

装饰器

我们在目录tornado项目core\decorators\open_handler下写一个装饰器,类作为装饰器 点击

class HandlerDecorate:
    """路由装饰器
    1. 实质上路由装饰器只是给装饰的类添加了__url_path__的属性
    2. 我们初始化的时候就通过__url_path__这个属性来判断当前的类是路由的处理器
    3. __url_path_index__用来给路由进行排序
    """

    def __init__(self, path, index=None) -> None:
        self.__url_path__ = path
        self.__url_path_index__ = index

    def __call__(self, cls):
        cls.__url_path__ = self.__url_path__
        cls.__url_path_index__ = self.__url_path_index__

        return cls

我们在__init__.py中暴露这个装饰器

from core.decorators.open_handler.index import HandlerDecorate

open_handler = HandlerDecorate

只要经过@open_hander修饰的类,就会含有__url_paht__属性,如

@open_handler(path="/api/(.*)", index=1)
class openApiHandlerService(RequestHandler):
    def get(self, *args, **kwargs):
        self.write("hello world")
        self.finish()

那么,openApiHandlerService就会含有__url_paht__属性为/api/(.*)

路由的收集

定义get_handlers方法,来获取被装饰器修饰的类

遍历项目文件

我们需要定义一个遍历项目文件的函数,当前函数用于查找项目中被open_handler修饰的类

我们在core\utils\module_utils.py下,新建一个函数,用于遍历得到某文件下的所有的module

import importlib
import pkgutil
import os

def get_all_modules(path, file_name):
    """
    获取路径下的所有file_name的module
    """
    # 获取目录的配置(目录必须是一个包,才会有__path__属性)
    _app = importlib.import_module(path)

    def get_all_moudules_name(package_path, prefix=""):
        # 用于深度遍历文件夹
        for loader, name, is_package in pkgutil.iter_modules([package_path]):
            if is_package:
                # 如果还是一个包,那么再次遍历,且遍历的时候加上前缀
                for _name in get_all_moudules_name(os.path.join(package_path, name), prefix=f"{name}."):
                    yield prefix + _name
            else:
                yield prefix + name

    return [
        importlib.import_module(f"{path}.{module_name}")
        for module_name in get_all_moudules_name(_app.__path__[0])
        if module_name.split(".")[-1][:len(file_name)] == file_name
    ]
  • import_module 点击 ,获取模块中的函数、属性等
  • iter_modules 点击,获取模块

为了规范,我们所有的路由定义的类都凡在开都为handlers的文件中

获取项目下所有的路由

我们在core\decorators\open_handler下新建一个OpenHandler的类,并定义一个get_handlers的方法用来获取所有的路由

class OpenHandler:
    """路由容器
    1. 初始化的时候获取路由的容器类和工具类
    2. 返回tornado路由列表
    """

    def __init__(self, source_libs) -> None:
        self.source_libs = source_libs   # 传递目录名,用于获取目录下所有使用装饰器的类
        self.handler_libs = []  # 存储路由的容器

    def get_handlers(self):
        self._handler_libs_ = []
        _modules = []  # 目录下所有的moudule容器
        for _path in self.source_libs:
            _modules += get_all_modules(_path, "handler")

        for _module in _modules:
            self.handler_libs += [
                dict(
                    path=_member.__url_path__,
                    handler=f"{_member.__module__}.{_member.__name__}",
                    index = _member.__url_path_index__
                )
                for _name,_member in inspect.getmembers(_module, inspect.isclass)
                if hasattr(_member, "__url_path__")
            ]

        # 排序
        self.handler_libs.sort(key=lambda x: x['index'])

        # 生成tornado的路由对象
        _result = []
        for _handler_lib in self.handler_libs:
            # 遍历生成tornado的路由对象
            _path = _handler_lib.get("path")
            _result.append(
                url(_path, import_object(_handler_lib.get("handler"))))

        # 所有的路由列表
        return _result

注册路由

一般我们在启动项目的时候需要注册路由

获取handler下的所有路由

为了项目规范我们把所有的路由都注册在了命名为handler的文件夹下,在启动环境的时候,我们一般调用Environment类下的方法,我们在Environment下,写一个获取handler下的路由的方法

class Environment:
	...

    def get_all_handlers(self):
        open_handler = OpenHandler(["core"])
        return open_handler.get_handlers()

他所表示的是获取core文件夹下的所有的路由,然后我们进行路由的注册

class Application(Application):
    def __init__(self):
        # 初始化数据库、redis等,项目启动的时候,不要引入模型类
        # 注册路由
        handlers = environment.get_all_handlers()
        # 添加动态路由
        super().__init__(handlers, **config.settings)

测试

  1. 启动项目,我们输入http://localhost:8888/api/,就会发现我们可以访问到注册的路由了
  2. 在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值