內置的模板引擎支持常見的格式(HTML、XML等)。可是你也能夠輕鬆地按需添加本身的格式。html
template會向輸出的結果中添加靜態及動態的內容。以下面這樣一個簡單模板:api
foo @bar baz
裏邊包含了兩個靜態的部分(foo 和 baz),它們環繞了一個動態部分(bar)。模板引擎組合它們而後輸出結果。事實上,爲了防止XSS跨站攻擊,bar須要在組合以前進行轉義。如在HTML中 須要將 "<" 轉爲 "<"。ui
模板怎麼知道每一個模板引擎要關聯的格式呢?它會根據後綴名查找:如一個以 .scala.html 結尾的模板將關聯到HTML格式。spa
最後,你一般但願你的模板會輸出爲HTTP響應體,所以你必須定義如何用模板來渲染Play的result。scala
總而言之,爲了支持自定義格式,必須作到下面這些步驟:code
實現 play.twirl.api.Format[A] trait中的 raw(text: String): A 及 escape(text: String): A 方法。Play將用它們來組合動態及靜態內容。orm
泛型A表示模板渲染的result類型,如 HTML模板對應着Html。A必須是play.twirl.api.Appendable[A] 特質的子類,這裏邊具體的定義瞭如何將各部分組合在一塊兒。htm
簡單起見,Play提供了 play.twirl.api.BufferedContent[A] 抽象來來實現 play.twirl.api.Appendable[A],它裏邊使用了一個StringBuilder 來構建result。同時它還實現了 play.twirl.api.Content 特質,所以Play知道如何來將它序列化爲HTTP response body(見本章最後一段)。模板引擎
簡單來講,你須要寫兩個類:一個定義result(實現 play.twirl.api.Appendable[A]),另外一個定義文本處理(實現 play.twirl.api.Format[A])。下邊是源碼中HTML的例子:ci
// 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 = … }
在build過程當中,整個項目編譯以前,模板都會先被編譯爲 .scala 文件。sbt設置中的 TwirlKeys.templateFormats(Map[String, String]) 定義了文件擴展名和模板格式之間的關係。例如,若是Play沒有內置支持HTML,你須要在TwirlKeys.templateFormats 作以下配置:
TwirlKeys.templateFormats += ("html" -> "my.HtmlFormat.instance")
注意箭頭符號右邊的類型必須是play.twirl.api.Format[_]。
只要域中存在play.api.http.Writeable[A]類型的隱式變量,Play就能夠直接將類型A轉換爲HTTP response。所以你須要作的就是爲你的自定義類型來定義這樣一個變量。下面仍是以HTTP爲例:
implicit def writableHttp(implicit codec: Codec): Writeable[Http] = Writeable[Http](result => codec.encode(result.body), Some(ContentTypes.HTTP))
注意:若是你的模板result類型是 play.twirl.api.BufferedContent 的子類,你只須要定義一個隱式的 play.api.http.ContentTypeOf 值:
implicit def contentTypeHttp(implicit codec: Codec): ContentTypeOf[Http] = ContentTypeOf[Http](Some(ContentTypes.HTTP))