KTOR DSL - 如何嵌套模板?

Posted

技术标签:

【中文标题】KTOR DSL - 如何嵌套模板?【英文标题】:KTOR DSL - how to nest templates? 【发布时间】:2021-07-02 17:11:49 【问题描述】:

我正在尝试使用 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 完成的一件显而易见的事情——有人知道我可能会错过什么吗?

【问题讨论】:

显示您的PageTemplate 课程 由于 API 笨拙,这一点并不明显。 @МихаилНафталь 我已经用 PageTemplate 类的示例更新了这个问题 【参考方案1】:

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

如果事先不知道Template 的类型,那么PageTemplate 类应该成为泛型并接受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*/
        
    

【讨论】:

【参考方案2】:

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

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

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

【讨论】:

以上是关于KTOR DSL - 如何嵌套模板?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Ktor 中构建嵌套路由?

Kotlin ktor 暴露 DSL 插入参考

通过 Docker 启动 Ktor 应用程序会导致:未配置 Koin 上下文。请使用 startKoin 或 koinApplication DSL

如何使用 Ktor 服务器向其他服务器发送 POST 请求?

Elasticsearch 8.X DSL 如何优化更有助于提升检索性能?

Elasticsearch 8.X DSL 如何优化更有助于提升检索性能?