KTOR DSL - 如何嵌套模板?

KTOR DSL - how to nest templates?

我正在尝试使用 KTOR DSL 将 HTML 模板相互嵌套,看起来应该非常简单,但文档让我无处可去,我尝试过的任何东西都没有编译或成功了。

我定义了一个根级页面模板,它需要一个名为 'pageContent' 的占位符,我正在尝试使用路由来确定应将哪个页面级模板注入为 HTML内容。所以 PageTemplate 看起来像这样:

class PageTemplate(private val username: String, private val displayName: String) : Template<HTML> {
    val pageContent = Placeholder<FlowContent>()
    
    override fun HTML.apply() {
        head {
            title { +"Page Title" }
            stylelink("lots of style and script, etc")
        }
        body("body classes") {
            header {...} //display logged-in user's name here, nav, etc
            main("some classes") {
                insert(pageContent)
            }
        }
    }
}

我的路由看起来像这样:

get("/example-path") {
    call.respondHtmlTemplate(PageTemplate(call.session?.username, call.session?.displayName)) {
        pageContent {
            ExamplePathTemplate(call.session?.username)
        }
    }
}

想法是让每个路由都用自己的路径特定模板覆盖 pageContent。

上面的代码可以编译。但是,当我 运行 它时,实际上从未调用过 ExamplePathTemplate 。我也尝试过使用 insert(ExamplePathTemplate(...), pageContent) 的变体,但由于某种类型不匹配而无法编译。感觉这应该是我应该能够用 KTOR 完成的一件显而易见的事情——有人知道我可能遗漏了什么吗?

通过将路由更改为如下所示,我能够获得页面特定的模板以应用于页面内容:

get("/example-path") {
    call.respondHtmlTemplate(PageTemplate(call.session?.username, call.session?.displayName)) {
        pageContent {
            insert(ExamplePathTemplate(call.session?.username)) { }
        }
    }
}

这满足了编译器的类型要求,并成功地用插入模板生成的 html 覆盖了 pageContent 占位符。

如果pageContent 属性是另一个模板的占位符,那么它的类型应该是TemplatePlaceholder,而不是简单的Placeholder.

如果事先不知道 Template 的类型,那么 PageTemplate class 应该变成泛型并接受 Template 的实例作为参数:

class PageTemplate<T : Template<FlowContent>>(private val username: String, private val displayName: String, private val template: T) : Template<HTML> {
    val pageContent = TemplatePlaceholder<T>()

    override fun HTML.apply() {
        head {
            title { +"Page Title" }
        }
        body("body classes") {
            header {/*...*/ } //display logged-in user's name here, nav, etc
            main("some classes") {
                insert(template, pageContent)
            }
        }
    }
}

用法:

get("/example-path") {
    call.respondHtmlTemplate(PageTemplate(call.session?.username, call.session?.displayName, ExamplePathTemplate(call.session?.username))) {
        pageContent { //this: ExamplePathTemplate
            /*set inner template parameters here*/
        }
    }
}