§为模板引擎添加对自定义格式的支持
内置模板引擎支持常见的模板格式(HTML、XML 等),但您也可以轻松地添加对您自己的格式的支持(如果需要)。本页总结了支持自定义格式的步骤。
§模板过程概述
模板引擎通过追加模板的静态和动态内容部分来构建其结果。例如,考虑以下模板
foo @bar baz
它包含两个静态部分(foo
和 baz
)以及一个动态部分(bar
)。模板引擎将这些部分连接在一起以构建其结果。实际上,为了防止跨站点脚本攻击,bar
的值可以在连接到结果的其余部分之前进行转义。此转义过程特定于每种格式:例如,在 HTML 的情况下,您希望将“<”转换为“<”。
模板引擎如何知道哪种格式对应于模板文件?它查看其扩展名:例如,如果它以 .scala.html
结尾,它将 HTML 格式与该文件关联。
最后,您通常希望您的模板文件用作 HTTP 响应的主体,因此您必须定义如何从模板渲染结果创建 Play 结果。
总之,要支持您自己的模板格式,您需要执行以下步骤
- 实现该格式的文本集成过程;
- 将文件扩展名与该格式关联;
- 最终告诉 Play 如何将模板渲染的结果作为 HTTP 响应主体发送。
§实现格式
实现 play.twirl.api.Format[A]
特征,该特征具有 raw(text: String): A
和 escape(text: String): A
方法,它们将分别用于集成静态和动态模板部分。
格式的类型参数 A
定义了模板渲染的结果类型,例如 HTML 模板的 Html
。此类型必须是 play.twirl.api.Appendable[A]
特征的子类型,该特征定义了如何将部分连接在一起。
为了方便起见,Play 提供了一个 play.twirl.api.BufferedContent[A]
抽象类,它使用 StringBuilder
来构建其结果并实现 play.twirl.api.Appendable[A]
,并且实现了 play.twirl.api.Content
特征,因此 Play 知道如何将其序列化为 HTTP 响应主体(有关详细信息,请参见本页的最后一部分)。
简而言之,您需要编写两个类:一个定义结果(实现 play.twirl.api.Appendable[A]
),另一个定义文本集成过程(实现 play.twirl.api.Format[A]
)。例如,以下是 HTML 格式的定义方式
// The `Html` result type. We extend `BufferedContent[Html]` rather than just `Appendable[Html]` so
// Play knows how to make an HTTP result from a `Html` value
class Html(buffer: StringBuilder) extends BufferedContent[Html](buffer) {
val contentType = MimeTypes.HTML
}
object HtmlFormat extends Format[Html] {
def raw(text: String): Html = …
def escape(text: String): Html = …
}
§将文件扩展名与格式关联
模板在构建过程中的编译整个应用程序源代码之前被编译成 .scala
文件。TwirlKeys.templateFormats
键是类型为 Map[String, String]
的 sbt 设置,定义了文件扩展名和模板格式之间的映射。例如,如果 Play 不开箱即用地支持 HTML,则需要在构建文件中编写以下内容以将 .scala.html
文件与 play.twirl.api.HtmlFormat
格式关联
TwirlKeys.templateFormats += ("html" -> "my.HtmlFormat.instance")
请注意,箭头右侧包含类型为 play.twirl.api.Format[_]
的值的完全限定名称。
§告诉 Play 如何从模板结果类型创建 HTTP 结果
Play 可以为任何类型为 A
的值写入 HTTP 响应主体,对于该值,存在隐式 play.api.http.Writeable[A]
值。因此,您只需要为模板结果类型定义这样的值。例如,以下是为 HTTP 定义此类值的方式
implicit def writableHttp(implicit codec: Codec): Writeable[Http] =
Writeable[Http](result => codec.encode(result.body), Some(ContentTypes.HTTP))
注意:如果您的模板结果类型扩展了
play.twirl.api.BufferedContent
,您只需要定义一个
隐式play.api.http.ContentTypeOf
值implicit def contentTypeHttp(implicit codec: Codec): ContentTypeOf[Http] = ContentTypeOf[Http](Some(ContentTypes.HTTP))
下一步:表单提交和验证
发现文档中的错误? 此页面的源代码可以在 这里 找到。 阅读完 文档指南 后,请随时贡献拉取请求。 有问题或建议要分享? 前往 我们的社区论坛 与社区展开讨论。