ahserver/aidocs/myTE.md
2025-10-05 12:07:12 +08:00

6.7 KiB
Raw Blame History

模板引擎技术文档

概述

本模块实现了一个基于 Jinja2 的自定义模板引擎系统,支持通过 URL 映射到文件路径的方式加载模板,并集成了异步渲染功能。该系统适用于 Web 服务中动态页面的生成和管理。

主要特性包括:

  • 自定义模板加载器(TmplLoader),支持多路径查找、继承机制与索引页自动识别。
  • 支持配置化的编码格式读取模板文件。
  • 异步渲染能力(render_async)。
  • 与项目中的 Url2FileServerEnv 组件无缝集成。

模块依赖

import os
import codecs

from appPublic.Singleton import SingletonDecorator
from appPublic.jsonConfig import getConfig

from jinja2 import Template, Environment, BaseLoader

from .serverenv import ServerEnv
from .url2file import Url2File, TmplUrl2File

说明

  • appPublic: 项目公共库,提供单例模式和 JSON 配置读取功能。
  • jinja2: 核心模板引擎库。
  • serverenv: 服务器运行环境对象,用于全局共享资源。
  • url2file: 将 URL 路径转换为本地文件路径的工具类,TmplUrl2File 是其针对模板的扩展。

核心类定义

TmplLoader(BaseLoader, TmplUrl2File)

自定义 Jinja2 模板加载器,结合了 BaseLoaderTmplUrl2File 的功能,支持从多个路径中按规则查找 .tmpl 类型的模板文件。

构造函数

def __init__(self, paths, indexes, subffixes=['.tmpl'], inherit=False)
参数 类型 描述
paths list[str] 模板文件搜索路径列表,按顺序查找。
indexes list[str] 索引页名称(如 index.tmpl, default.tmpl),用于目录访问时自动匹配默认页。
subffixes list[str] 允许的模板文件后缀,默认为 ['.tmpl']。可扩展支持其他后缀。
inherit bool 是否启用路径继承机制(由 TmplUrl2File 实现)。

⚠️ 注意:需同时调用父类 BaseLoaderTmplUrl2File 的初始化方法。

方法

get_source(env: Environment, template: str) -> tuple[str, str, callable]

获取指定模板的源码内容。

返回值(符合 Jinja2 加载器规范):

  • source: 模板文本内容(字符串)
  • filename: 实际文件路径
  • uptodate: 可调用对象,判断文件是否被修改(基于 mtime

流程说明

  1. 读取全局配置中的网站编码(config.website.coding)。
  2. 使用 url2file() 将模板名映射为实际文件路径。
  3. 若文件不存在,抛出 TemplateNotFound 错误。
  4. 以指定编码读取文件内容。
  5. 返回 (source, filepath, is_unchanged_lambda)
join_path(name: str, parent: str) -> str

实现模板中 {% extends %}{% include %} 时相对路径的解析。

使用 TmplUrl2File.relatedurl() 计算相对于父模板的路径。

list_templates() -> list

当前未实现模板枚举功能,固定返回空列表。

后续可扩展为扫描所有路径下的模板并去重返回。


TemplateEngine(Environment)

封装 Jinja2 Environment 的模板执行环境,提供更便捷的异步渲染接口。

构造函数

def __init__(self, loader=None)
参数 类型 描述
loader TmplLoader 模板加载器实例,若不传则使用默认加载器。

额外属性

  • urlpaths: (预留字段)可用于缓存 URL 到模板的映射。
  • loader: 保存引用以便内部调用。

方法

join_path(template: str, parent: str) -> str

代理至 self.loader.join_path(),确保路径解析一致性。

async render(___name: str, **globals) -> str

异步渲染指定模板。

参数 类型 描述
___name str 模板名称URL 风格路径)
**globals dict 渲染上下文变量

逻辑步骤

  1. 调用 get_template() 获取模板对象。
  2. 执行 render_async() 进行异步渲染。
  3. 返回渲染后的 HTML 字符串。

支持异步过滤器、协程调用等高级特性。


初始化函数

setupTemplateEngine() -> None

全局设置函数,用于初始化模板引擎并注入到服务器环境中。

功能流程

  1. 读取配置:getConfig() 获取全局配置对象。
  2. 提取处理器配置中类型为 'tmpl' 的后缀列表:
    subffixes = [i[0] for i in config.website.processors if i[1] == 'tmpl']
    
    示例:若配置为 [('.html', 'tmpl'), ('.tmpl', 'tmpl')],则支持 .html.tmpl 文件作为模板。
  3. 创建 TmplLoader 实例,启用继承模式。
  4. 初始化 TemplateEngine 并绑定加载器。
  5. 将引擎挂载到单例 ServerEnv()tmpl_engine 属性上,供全局使用。

示例配置片段JSON/YAML

{
  "website": {
    "coding": "utf-8",
    "paths": [
      "/var/www/templates",
      "/opt/app/default_tmpl"
    ],
    "indexes": ["index.tmpl", "default.tmpl"],
    "processors": [
      [".html", "tmpl"],
      [".tmpl", "tmpl"],
      [".js", "static"]
    ]
  }
}

使用示例

# 初始化模板引擎(通常在应用启动时调用一次)
setupTemplateEngine()

# 获取引擎实例
g = ServerEnv()
engine = g.tmpl_engine

# 异步渲染模板
result = await engine.render('/user/profile.html', name='Alice', age=30)

print(result)  # 输出渲染后的 HTML 内容

在模板中也可以使用继承或包含:

{# base.tmpl #}
<html><body>{% block content %}{% endblock %}</body></html>
{# profile.tmpl #}
{% extends "base.tmpl" %}
{% block content %}
  <h1>Hello {{ name }}</h1>
{% endblock %}

注意事项

  1. 编码问题:确保 config.website.coding 设置正确(通常为 "utf-8"),避免中文乱码。
  2. 文件权限:模板所在目录需对运行进程可读。
  3. 性能建议
    • 生产环境应开启 Jinja2 缓存机制(当前未配置)。
    • 可考虑实现 list_templates() 以支持热重载检测。
  4. 异常处理
    • TemplateNotFound: 模板文件未找到。
    • OSError: 文件读取失败(权限、磁盘错误等)。

扩展建议

功能 建议
缓存支持 添加 cache_size 参数并启用 Jinja2 的模板缓存
自动重载 监听文件变化,在开发模式下自动刷新模板
安全沙箱 对不可信模板启用沙箱执行环境
多租户支持 按用户/站点隔离 pathsloader 实例

版权与维护

  • 作者:项目开发团队
  • 所属模块app.template_engine
  • 最后更新2025年4月5日

文档版本v1.0
适用于代码版本:见 Git 提交记录