Play具有高效的模板体系,采用Groovy作为其表达式语言,允许动态生成HTML、XML、JSON或者任何基于文本格式的文档,并且具有创建可重用标签(tag)的功能。模板储存在Play应用的app/views目录下。
1、模板语法
与其他的语言一样,Play的模板也具有严格定义的语法。模板语法被划分为多种元素,用于完成不同类型的任务。Play模板的本质是普通的文本文件,其中带有占位符的部分可以生成动态内容。模板的动态部分采用Groovy语言编写,其语法与Java非常类似。框架可以将需要渲染的结果追加至HTTP响应的数据部分,并发送至模板。所有的动态部分将会在模板的执行期间被解析。
(表1 模板语法)
元素 | 描述 | 语法 |
---|---|---|
表达式 | 用于输出表达式的值。如 ${note.title} 的作用是将域对象note的属性title的值输出。 | ${...} |
标签 | 用于调用Play框架内置的或是开发人员自定义的标签。如#{get 'title' /}:获取变量 title 的值,该值仅在模板页面中有效。 | #{...} |
引用 | 用于生成调用控制器中Action方法的URL,在页面链接中使用的最为频繁。@{...} 和 @@{...} 的区别在于生成的URL分别是相对路径还是绝对路径。如: 1.<a href="@{Application.index()}">首页</a>:生成指向首页的链接。 2.@{'/public/stylesheets/main.css'}:引入CSS静态资源文件。 | @{...} 和@@{...} |
国际化 | 用于显示经过国际化处理后的消息内容。 | &{...} |
注释 | 用于在模板中添加注释。如:*{ 这是注释 }*。 | *{...}* |
脚本 | 用于添加复杂的 Groovy 脚本,可以声明变量和执行业务逻辑。 | %{...}% |
1.1 表达式(expression):${…}
构建动态部分最简单的方法就是声明表达式。表达式需要以 ${ 开头, 并以 } 结尾,作为占位符使用。具体例子如下:
<h1>Client ${client.name}</h1>
如果不能确定向模板注入的client对象是否为null,可以使用如下Groovy快捷语法:
<h1>Client ${client?.name}</h1>
1.2 标签(tag): #{tagName /}#
标签是能够附带参数调用的模板片段,如果标签只有一个参数,按照约定,参数的名称为arg,并且该参数名是可以省略的。例如,可以使用#{script}标签加载JavaScript文件:#{script 'jquery.js' /}
Play模板中的标签必须是闭合的,可以通过两种方式闭合标签。采用直接闭合的形式:
#{script 'jquery.js'/}
#{script 'jquery.js'}#{/script}
<h1>Client ${client.name}</h1>
<ul>
#{list items:client.accounts, as:'account' }
<li>${account}</li>
#{/list}
</ul>
在应用中,模板引擎默认对所有的动态表达式进行转义,以此来避免XSS的安全问题。如果模板中变量${title}的内容为<h1>Title</h1>,在页面输出时会自动进行转义:
${title} --> <h1>Title</h1>
也可以通过调用扩展方法raw(),以非转义的形式在页面中输出,具体使用方法如下:
${title.raw()} --> <h1>Title</h1>
如果需要显示大量的非转义HTML内容,可以使用#{verbatim /}标签:
#{verbatim}
${title} --> <h1>Title</h1>
#{/verbatim}
1.3 引用(action):@{…}或者@@{…}#
在前面的章节已经有过一些介绍,Play通过路由器可以(逆向)生成URL,匹配指定的路由。在模板中使用@{…}引用可以达到相同的目的:
<h1>Client ${client.name}</h1>
<p>
<a href="@{Clients.showAccounts(client.id)}">All accounts</a>
</p>
<hr />
<a href="@{Clients.index()}">Back</a>
@@{…}引用的使用语法与@{…}相同,只不过生成的是绝对URL(尤其适用于邮箱)。
1.4 国际化(messages):&{…}#
如果应用需要进行国际化操作,那么可以在模板中使用&{...}显示国际化信息。需要进行国际化的应用首先需要在conf/messages文件中进行国际化定义:
clientName=The client name is %s
之后在模板中就可以通过&{...}显示该国际化信息了:
<h1>&{'clientName',client.name}</h1>
1.5 注释(comment):*{…}*#
使用*{…}*标记的内容会被模板引擎忽略,起到注释作用:
*{**** Display the user name ****}*
<div class="name">
${user.name}
</div>
1.6 脚本(script): %{…}%#
脚本是更加复杂的表达式集合,能够声明一些变量或者定义一些语句。Play的模板中使用%{…}%插入脚本:
%{
fullName = client.name.toUpperCase()+' '+client.forname;
}%
<h1>Client ${fullName}</h1>
也可以直接使用out内置对象输出动态内容:
%{
fullName = client.name.toUpperCase()+' '+client.forname;
out.print('<h1>'+fullName+'</h1>');
}%
在模板中还可以使用脚本编写结构化语句,执行一些逻辑操作,比如迭代:
<h1>Client ${client.name}</h1>
<ul>
%{
for(account in client.accounts) {
}%
<li>${account}</li>
%{
}
}%
</ul>
使用模板时切记:模板不适合处理复杂的业务逻辑,所以在模板中请尽量使用标签,或者直接将处理交给控制器或模型对象。
2、模板继承
Play提供继承机制为多模板之间进行页面布局或设计提供服务。#{extends /} 和 #{doLayout /}可以使页面的共享和重用变得更加方便简洁,同时也能够帮助开发人员实现页面中动态内容和静态外观装饰的分离。在模板与装饰之间可以使用#{get}和#{set}标签进行参数传递。
将simpledesign.html定义为父模板,也就是装饰模板。可以将页面中重用的静态内容定义在装饰模板中,如导航条、页面顶端的图片banner、页面底端的footer说明等。
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>#{get 'title' /}</title>
<link rel="stylesheet" type="text/css" href="@{'/public/stylesheets/main.css'}" />
</head>
<body>
<h1>#{get 'title' /}</h1>
#{doLayout /}
<div class="footer">Built with the play! framework</div>
</body>
</html>
其他页面使用#{extends}标签可以非常简单地植入该装饰模板,具体使用方法如下:
#{extends 'simpledesign.html' /}
#{set title:'A decorated page' /}
This content will be decorated.