Play Framework Web开发教程(32): 模板基本知识和一些通用结构

本篇介绍Play模板的一些基本用法,之后你可以编写View模板来实现MVC中的View部分。
@特殊符号
在Scala模板中,@符号表现Scala表达式的开始。和其它Web框架一些模板不同的是,Play的View模板没有使用特殊的符号作为表达式的结束符。Play的模板编译器自动根据上下文判断Scala表达式是否结束。这样可以使得编写View模板变得非常简洁:

Hello @name!
Your age is @user.age.

本例的第一行,name为一Scala表达式,第二行中,user.age也是表达式。而age后的”.”不是表达式的一部分。那么些吗的例子中:

Next year, your age will be @user.age + 1

Scala表达式也只到user.age为止,如果你需要表示比age大一年,那么需要使用括号:

Next year, your age will be @(user.age + 1)

有时,你需要使用多个Scala语句,那么需要使用{},比如:

Next year, your age will be
@{val ageNextYear = user.age + 1; ageNextYear}

在{}之间你可以使用任意的scala语句。
因为@是特殊字符,如果你需要输出@符号本身,那么你需要使用另外一个@进行转义,比如:

username@@example.com

模板使用@* *@作为注释,多条Scala表达式可以使用Scala语言的注释语法结构。 模板编译器不会在编译后的HTML文档中输出注释。
表达式
模板中Scala表达式可以使用任意的Scala语句,Play自动添加如下的API包到View模板中:

■ models._
■ controllers._
■ play.api.i18n._
■ play.api.mvc._
■ play.api.data._
■ views.%format%._

 
引入models._ 和controllers._ 可以保证在View模板中可以使用定义的Model和Controller类。 i18n定义的语言本地化和全球化支持。mvc._引入MVC相关的部件。data._定义了表单(form)和数据校验相关的类定义,而views.%format% 根据你定义的View模板格式而定,比如你使用html格式的模板,那么你引入views.html._,它定义了一些HTML辅助函数方便生成HTML。

显示集合类型数据
在Play中使用集合类型的地方非常多,比如显示用户列表,文章列表,产品目录,分类或者标签,比如我们可以使用下面的代码显示文章的名称:

<ul>
@articles.map { article =>
<li>@article.name</li>
}
</ul>

或者使用for-表达式(View编译器自动添加yeild关键字,因为没有yield,for表达式不会生成任何结果,因此你使用for表达式时可以省略掉yield部分)

<ul>
@for(article <- articles) {
	<li>@article.name</li>
}
</ul>

安全和转义
应用的开发者应该总是把安全放在心上,当处理View模板时,cross-site 脚本的安全漏洞要非常注意。 在允许用户输入的情况下,要注意HTML注入的风险,下图给出了一个使用cross-site 脚本攻击网站的示意图:

20140915001

因此我们需要使用HTML转义来避免这种情况。对于Play的View模板引擎来说,不是每个值都是同等对待的,比如对于字符串banana来说,如果我们需要在一个HTML文档中显示这个字符串,我们需要判断这是一个HTML代码片段,还是一个普通的字符串,如果是HTML代码片段,那么需要直接输出banana,如果是作为普通字符串来显示,那么需要对< / > 进行转义,因为它们是特殊字符串,那么我们需要输出:<b>banana</b>
有时你可能会觉得糊涂,究竟什么时候需要转义,对于Play来说,你在View模板中使用的字面量都被Play认为是HTML语句片段,不经转义直接输出。这是因为总是由开发人员来编写View模板,因此通常是认为安全的。但其中的Scala语句的输出都经过转义。比如我们由如下的View模板:

@(review: Review)
<h1>Review</h1>
<p>By: @review.author</p>
<p>@review.content</p>

我们使用如下代码来显示一个页面:

val review = Review("John Doe", "This article is <b>awesome!</b>")
Ok(views.html.basicconstructs.escaping(review))

这将显示如下页面:
20140915002

这正是我们所需要的,我们不希望用户输入的内容是HTML代码片段,也就是不允许用户输入使用HTML标记。

一般情况下,Scala语句部分输出是经过转义的,如果你需要阻止这种缺省行为 ,可以使用Html封装一下,此外你还可以使用Scala的XML函数库,直接输出HTML代码,例如:

@{
	<b>hello</b>
}

这里的hello也是没有转义的。