文档

§模板引擎

§基于 Scala 的类型安全模板引擎

Play 附带了 Twirl,这是一个强大的基于 Scala 的模板引擎,其设计灵感来自 ASP.NET Razor。具体来说,它

注意: 尽管模板引擎使用 Scala 作为表达式语言,但这对 Java 开发人员来说不是问题。您几乎可以像使用 Java 一样使用它。

请记住,模板不是编写复杂逻辑的地方。您无需在此处编写复杂的 Scala 代码。大多数情况下,您只需访问模型对象中的数据,如下所示

myUser.getProfile().getUsername()

参数类型使用后缀语法指定。泛型类型使用 [] 符号而不是通常的 <> Java 语法指定。例如,您编写 List[String],它与 Java 中的 List<String> 相同。

模板是编译的,因此您将在浏览器中看到任何错误

§概述

Play Scala 模板是一个简单的文本文件,包含少量 Scala 代码块。模板可以生成任何基于文本的格式,例如 HTML、XML 或 CSV。

模板系统旨在让习惯使用 HTML 的用户感到舒适,使前端开发人员能够轻松地使用模板。

模板被编译为标准的 Scala 函数,遵循简单的命名约定。如果您创建一个 views/Application/index.scala.html 模板文件,它将生成一个 views.html.Application.index 类,该类具有一个 render() 方法。

例如,这是一个简单的模板

@(customer: Customer, orders: List[Order])

<h1>Welcome @customer.name!</h1>

<ul>
@for(order <- orders) {
  <li>@order.getTitle()</li>
}
</ul>

然后,您可以像通常在类上调用方法一样,从任何 Java 代码中调用它

Content html = views.html.Application.index.render(customer, orders);

§语法:神奇的“@”字符

Scala 模板使用 @ 作为唯一的特殊字符。每当遇到此字符时,它都表示动态语句的开始。您无需显式关闭代码块 - 动态语句的结束将从您的代码中推断出来

Hello @customer.getName()!
       ^^^^^^^^^^^^^^^^^^
          Dynamic code

由于模板引擎通过分析您的代码自动检测您的代码块的结束,因此此语法仅支持简单语句。如果您想插入多标记语句,请使用括号显式标记它

Hello @(customer.getFirstName() + customer.getLastName())!
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                          Dynamic Code

注意: 确保在动态语句的关键字和括号之间不要包含空格。

例如,以下代码不起作用

@for (menu <- menuList) { ... }  // Compilation error: '(' expected but ')' found.
    ^

您也可以使用花括号编写多语句块

Hello @{val name = customer.getFirstName() + customer.getLastName(); name}!
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                  Dynamic Code

由于 @ 是一个特殊字符,因此您有时需要对其进行转义。为此,请使用 @@

My email is bob@@example.com

§模板参数

模板就像一个函数,因此它需要参数,这些参数必须在模板文件的顶部声明

@(customer: models.Customer, orders: List[models.Order])

您也可以为参数使用默认值

@(title: String = "Home")

或者多个参数组

@(title:String)(body: Html)

§模板构造函数

默认情况下,模板被生成为一个静态函数,可以在任何上下文中调用。如果您的模板依赖于组件,例如消息 API,您可能会发现使用组件(和其他模板)注入它更容易,然后您可以将该模板注入使用它的控制器。

Twirl 支持为模板声明构造函数,在文件开头,模板参数之前使用 @this() 语法。构造函数的参数可以与模板参数以相同的方式定义。

@this(messagesApi: MessagesApi)

@(customer: models.Customer, orders: List[models.Order])

§迭代

您可以使用 for 关键字,以一种非常标准的方式

<ul>
@for(p <- products) {
  <li>@p.getName() ([email protected]())</li>
}
</ul>

注意: 确保 {for 在同一行,以指示表达式继续到下一行。

§If 块

If 块没有什么特别之处。只需使用 Scala 的标准 if 语句

@if(items.isEmpty()) {
  <h1>Nothing to display</h1>
} else {
  <h1>@items.size() items!</h1>
}

§声明可重用块

您可以创建可重用代码块

@display(product: models.Product) = {
  @product.getName() ([email protected]())
}

<ul>
@for(product <- products) {
  @display(product)
}
</ul>

请注意,您还可以声明可重用的纯代码块

@title(text: String) = @{
  text.split(' ').map(_.capitalize).mkString(" ")
}

<h1>@title("hello world")</h1>

注意: 在模板中以这种方式声明代码块有时可能有用,但请记住,模板不是编写复杂逻辑的最佳位置。通常最好将这些代码外部化到 Java 类中(如果您愿意,可以将其存储在 views/ 包下)。

按照惯例,以 implicit 开头的名称定义的可重用块将被标记为 implicit

@implicitFieldConstructor = @{ MyFieldConstructor() }

§声明可重用值

您可以使用 defining 助手定义作用域值

@defining(user.getFirstName() + " " + user.getLastName()) { fullName =>
  <div>Hello @fullName</div>
}

§导入语句

您可以在模板(或子模板)的开头导入任何您想要的内容

@(customer: models.Customer, orders: List[models.Order])

@import utils._

...

要进行绝对解析,请在导入语句中使用 root 前缀。

@import _root_.company.product.core._

如果您在所有模板中都需要一些常见的导入,您可以在 build.sbt 中声明

TwirlKeys.templateImports += "org.abc.backend._"

§注释

您可以在模板中使用 @* *@ 编写服务器端块注释

@*********************
 * This is a comment *
 *********************@

您可以在第一行添加注释,将您的模板文档到 Scala API 文档中

@*************************************
 * Home page.                        *
 *                                   *
 * @param msg The message to display *
 *************************************@
@(msg: String)

<h1>@msg</h1>

§转义

默认情况下,动态内容部分会根据模板类型(例如 HTML 或 XML)的规则进行转义。如果您想输出原始内容片段,请将其包装在模板内容类型中

注意: 使用此功能时,请考虑输出原始 HTML 的安全隐患,如果用户有可能控制内容。此技术是跨站点脚本 (XSS) 漏洞的常见原因,如果不谨慎使用,会很危险。

例如,要输出原始 HTML

<p>
  @Html(article.content)
</p>

下一步:使用模板进行依赖注入


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