Skip to content

模板引擎

SmartWeb 提供了轻量的服务端模板扩展协议,并附带 Rythm 实现。当前实现能够按 Controller 与 Action 名称发现模板,但生命周期接线尚未完成,因此应把它视为实验性功能,而不是已经完备的视图层。

模板发现约定

每个 Action 在启动扫描期按以下路径寻找模板:

text
<Controller 完整类名路径>/<actionMethod>.html

例如:

kotlin
package com.example

class UserController {
    fun profile(): User = TODO()
}

对应模板路径为:

text
com/example/UserController/profile.html

模板在 WebControllerLoader 创建 ActionInvoker 时解析一次,并保存在 WebActionInvoker 中;运行时不会为每次请求重新遍历模板引擎。

渲染条件与优先级

响应处理顺序为:

text
Render → Temple → null 状态码 → String/对象/文件等类型分派

同时满足以下条件时才会渲染模板:

  1. 启动扫描时为当前 Action 找到了模板。
  2. 请求 Accept 解析结果的第一个媒体类型严格等于 text/html

模板一旦命中,Action 的普通返回值不会直接参与渲染;模板从 WebActionContext.saves 读取数据。当前实现不是完整的内容协商:text/html 不是首项、通配符或带权重的复杂 Accept 值都应通过端到端测试确认。

在 Action 中传递变量

可以在 Before/Action 中直接写入 WebActionContext.saves@ContextValues 声明的参数也从同一份数据读取,具体绑定方式见请求与参数绑定。Rythm 渲染前还会自动加入:

名称内容
req当前 Request
resp当前 Response
context当前 WebActionContext

业务变量应使用不会与以上名称冲突的 key。

Rythm 模块

kotlin
implementation("com.IceCreamQAQ.SmartWeb.Temple:Rythm:1.0.0-DEV11")

模块配置声明为:

properties
web.temple.impl=rythm

Rythm 实现按运行模式读取不同位置:

模式模板来源
devsrc/main/resources/rythm/<模板路径> 文件
devclasspath 下 rythm/<模板路径> 资源

因此上例完整资源位置为:

text
src/main/resources/rythm/com/example/UserController/profile.html

开发模式把文件交给 Rythm,便于观察模板修改;生产模式在发现时读取 classpath 文本。

扩展协议

自定义实现需要提供 TempleEngine

kotlin
interface TempleEngine {
    fun start(isDevMode: Boolean)
    fun close()
    fun getTemple(path: String): Temple?
}

interface Temple {
    fun invoke(context: WebActionContext): String
}

多个 TempleEngine 会按注入列表顺序查找,首个返回非 null 的实现获胜。Temple.invoke 的结果固定按 text/html 写出;若需要状态码、Header 或其他媒体类型,应改用 Render

当前实现限制

生命周期尚未接通

源码定义了 TempleEngine.start(isDevMode)close(),但当前 SmartWeb 主流程没有调用它们;Rythm 的内部 RythmEngine 因而不会被框架自动初始化。仅添加依赖和配置还不足以保证模板可用。

此外还应注意:

  • web.temple.impl 配置当前没有直接连接到 WebControllerLoader.templeEngines 的源码路径,实际注入结果需要按所用 Rain DI 版本验证。
  • 模板是在 Controller 扫描期发现的;引擎必须在该阶段之前完成初始化。
  • 同名 Action 重载会映射到同一个模板路径,因为约定中不包含参数签名。
  • 模板异常没有独立错误模型,会进入普通 Action 异常与 500 处理链。
  • 当前只有 Rythm 实现,没有布局、国际化、缓存控制或统一 ViewModel 协议。

生产项目若需要服务端页面,建议先补齐引擎启动/关闭接线和集成测试;否则使用 JSON API、显式 Render,或在应用层自行管理模板引擎。

基于 Apache License 2.0 发布