§為範本引擎新增對自訂格式的支援
內建範本引擎支援常見的範本格式 (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 設定,定義檔案副檔名與範本格式之間的對應。例如,如果 HTML 沒有由 Play 內建支援,您必須在建置檔案中撰寫以下內容,將 .scala.html
檔案與 play.twirl.api.HtmlFormat
格式關聯
TwirlKeys.templateFormats += ("html" -> "my.HtmlFormat.instance")
請注意,箭頭右邊包含 play.twirl.api.Format[_]
類型值的完整限定名稱。
§告訴 Play 如何從範本結果類型產生 HTTP 結果
對於任何存在隱式 play.api.http.Writeable[A]
值的 A
類型值,Play 都可以撰寫 HTTP 回應主體。因此,您只需要為範本結果類型定義此類值即可。例如,以下是為 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))
下一步:表單提交和驗證
在此文件說明中發現錯誤?此頁面的原始碼可以在 這裡 找到。閱讀 文件說明指南 後,請隨時提出拉取請求。有問題或建議要分享?請前往 我們的社群論壇 與社群開始對話。