文档

§为模板引擎添加对自定义格式的支持

内置模板引擎支持常见的模板格式(HTML、XML 等),但您也可以轻松地添加对您自己的格式的支持(如果需要)。本页总结了支持自定义格式的步骤。

§模板过程概述

模板引擎通过追加模板的静态和动态内容部分来构建其结果。例如,考虑以下模板

foo @bar baz

它包含两个静态部分(foo  baz)以及一个动态部分(bar)。模板引擎将这些部分连接在一起以构建其结果。实际上,为了防止跨站点脚本攻击,bar 的值可以在连接到结果的其余部分之前进行转义。此转义过程特定于每种格式:例如,在 HTML 的情况下,您希望将“<”转换为“&lt;”。

模板引擎如何知道哪种格式对应于模板文件?它查看其扩展名:例如,如果它以 .scala.html 结尾,它将 HTML 格式与该文件关联。

最后,您通常希望您的模板文件用作 HTTP 响应的主体,因此您必须定义如何从模板渲染结果创建 Play 结果。

总之,要支持您自己的模板格式,您需要执行以下步骤

§实现格式

实现 play.twirl.api.Format[A] 特征,该特征具有 raw(text: String): Aescape(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))

下一步:表单提交和验证


发现文档中的错误? 此页面的源代码可以在 这里 找到。 阅读完 文档指南 后,请随时贡献拉取请求。 有问题或建议要分享? 前往 我们的社区论坛 与社区展开讨论。