视图存储在grails-app/views directory目录下。主要想学习如何创建Taglib和如何利用模板技术。
Grails使用GSP作为表现层,在GSP中groovy不只是表明GSP是基于什么技术的,而且还可以利用Groovy来创建一些脚本来在GSP中执行。在这点上说GSP和JSP很相像。
当然内嵌的脚本并不利于代码的重用。Grails中的Taglib和模板给你提供了一个很好的重用代码的途径。
GSP 是Grails的视图的基础。List页面提供到Show页面的连接,Show页面允许你导航到Edit页面。
MVC的分离策略主要是可以给应用程序不同的视图,Grails通过不同的插件来支持不同的表现层技术。可以通过命令grails install-plugin 来查看现在安装的插件。 或使用grails list-plugins来获得当前可用的插件。
虽然Grails 并不支持 native和
JSF,但是你还是可以使用他们。一个Grails程序就是一个标准的Java EE程序,因此只要你在lib目录中放置了正确的Jar文件,并在WEB-INF/web.xml文件中进行了正确的配置,就可以正常的使用了。Grails实在一个标准的servlet容器中开发的,所以Grails程序也支持JSP。
类似的增加Ajax框架也同样的简单,拷贝JavaScript库到web-app/js目录下。 Prototype和Scriptaculous是Grails默认安装的。RichUI插件可以很好的从Ajax库中选择正确的UI。
当查看插件列表时,可以看到对富客户端,如:Flex,OpenLazlo,GWT和ZK的支持。
在GSP文件中有许多有用的以<g:开头的标签。GSP文件就是Html和Grails标签的混合体。
在控制器中使用def scaffold 的作用是指示Grails动态的在运行的时候产生GSP文件。
输入命令 grails generate-all Trip会产生控制器和相关的GSP文件
当访问 http://localhost:9090/trip-planner/trip/list时,会先调用TripController来返回Trip的列表,并传递给list.gsp来显示。
下面介绍一些常用的Grails的标签,包括<g:each>。
<g:each>是个非常常用的Grails标签。它遍历列表中的每个元素,打开文件/trip/list.gsp 就可以看到如何使用这个标签:
<g:each in="${tripList}"
status="i" var="trip">
<tr
class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td><link action="show"
id="${trip.id}">${trip.id?.encodeAsHTML()}</g:link></td>
<td>${trip.airline?.encodeAsHTML()}</td>
<td>${trip.name?.encodeAsHTML()}</td>
<td>${trip.city?.encodeAsHTML()}</td>
<td>${trip.startDate?.encodeAsHTML()}</td>
<td>${trip.endDate?.encodeAsHTML()}</td>
</tr>
</g:each>
|
The status attribute in the在 <g:each>中,status就是一个简单的计数器。Var属性允许你定义一个当前元素的名字。
另一个Grails 标签是 <g:link>,它建立一个HTML的<a href>连接。<g:createLink>标签会创建一个真正的URL字符串。在list.gsp上部,你可以看到另一个和连接相关的标签<g:createLinkTo>,这个标签接受一个dir和 file属性:
<div class="nav">
<span
class="menuButton"><a class="home"
href="${createLinkTo(dir:'')}">Home</a></span>
<span
class="menuButton"><link class="create"
action="create">New Trip</g:link></span>
</div>
|
在list.gsp中还可以看到<g:if>标签:
<h1>Trip List</h1>
<if test="${flash.message}">
<div
class="message">${flash.message}</div>
</g:if>
|
<g:paginate>标签显示的是相关的分页逻辑;<g:sortable>把列的标题变成可点击的,用来进行排序。其他的一些标签,如:<g:form>和 <g:submit>指示显示相对应的html元素。
自定义标签库
虽然标准的Grails标签非常有用,但是最终你还是需要自己的标签。
在Grails中创建标签库要比在JSP中创建标签库方便。
在Grails中创建标签库的第一步是输入命令grails create-tag-lib Date。这样就会创建两个文件: grails-app/taglib/DateTagLib.groovy (标签库)和
grails-app/test/integration/DateTagLibTests.groovy (测试文件)向文件DateTagLib.groovy中添加以下的代码:
class DateTagLib {
def thisYear =
{
out <<
Calendar.getInstance().get(Calendar.YEAR)
}
}
|
这样就创建了<g:thisYear>标签,年的属性直接输出到输出流中。
测试标签库
在文件DateTagLibTests.groovy里添加如下的测试代码:
class DateTagLibTests extends GroovyTestCase {
def dateTagLib
void setUp(){
dateTagLib =
new DateTagLib()
}
void
testThisYear() {
String
expected = Calendar.getInstance().get(Calendar.YEAR)
assertEquals("the years don't match", expected,
dateTagLib.thisYear())
}
}
|
输入命令grails test-app来进行测试
命令grails test-app除了运行测试用例外,还会生成测试报告。打开文件test/reports/html/index.html可以进行查看。
这样这个标签就测试开发完了。
自定义标签的高级话题
大部分标签可以有body和属性。
class DateTagLib {
def thisYear =
{
out <<
Calendar.getInstance().get(Calendar.YEAR)
}
def copyright =
{ attrs, body ->
out <<
"<div id='copyright'>"
out <<
"© ${attrs['startYear']} - ${thisYear()}, ${body()}"
out <<
" All Rights Reserved."
out <<
"</div>"
}
}
|
注意attrs是一个包含标签属性的HashMap。可以通过这个HashMap来得到startYear属性。类似的body是作为一个Closure传递进来的。
默认的自定义的标签都放在g:命名空间下,如果想修改这个行为的话,需要在DateTagLib.groovy 中添加static namespace = 'trip'。这样在GSP中就可以使用以下的方式进行调用:<trip:copyright startYear="2002">FakeCo
Inc.</trip:copyright>。
模板
自定义标签库是重用代码的一个好的办法,但是大段的代码的好的重用方式是使用模板。
一个模板就是可以在多个GSP文件中共享的一段GSP代码。在the
grails-app/views/trip 目录下创建的文件,只有Trip的视图才能访问。只有在grails-app/views 目录下创建的文件才能全局共享。创建如下的全局模板:
<div id="footer">
<g:copyright
startYear='2002'>FakeCo, Inc.</g:copyright>
<div
id="powered-by">
<img
src="${createLinkTo(dir:'images', file:'grails-powered.jpg')}"
/>
</div>
</div>
|
下面来在相应的视图中引入这个模板:
<html><body>
...
<g:render template="/footer" />
</body></html>
|
自定义scaffolding
为了自定义 scaffolding,需要使用命令grails install-templates。这个命令会向项目添加一个新的目录src/templates。在这个目录下会有三个子目录artifacts、scaffolding和war。
artifacts 目录中保存的是生成Controller、DomainClass和TagLib时需要使用的模板。比如:如果想要所有的控制器都扩展一个相同的抽象类。
war 目录包含一个web.xml文件。如果需要添加自定义的参数,如:filters 或者 servlets,都可以在这个文件中进行。但你使用grails war命令时,这个文件就会被包含在生成的war文件中。
scaffolding 目录中包含的是生成视图时,需要指定的信息。打开 list.gsp 然后添加 <g:render template="/footer" />到文件的底部。