一个GPS通常拥有一个"model",它是变量集被用于视图渲染。通过一个控制器model被传递到GSP视图。例如,考虑下列控制器的操作:
def show = {
[book: Book.get(params.id)]
}
这个操作将查找一个
Book
实体,并创建一个包含关键字为
book
的model,这个关键字可在随后的GSP视图中应用:
<%=book.title%>
GSP支持使用
<% %>
来嵌入Groovy代码(这是不推荐的):
<html>
<body>
<% out << "Hello GSP!" %>
</body>
</html>
同样,你可以使用
<%= %>
语法来输出值:
html>
<body>
<%="Hello GSP!" %>
</body>
</html>
在
<% %>
中你当然可以声明变量:
<% now = new Date() %>
然后,在页面中的之后部分可以重复使用
<%=now%>
然而, 在GSP中存在着一些预先定义的变量,包括:
application
- javax.servlet.ServletContext实例applicationContext
Spring ApplicationContext实例flash
- flash 对象grailsApplication
- GrailsApplication 实例out
- 响应输出流params
-params对象用于检索请求参数request
- HttpServletRequest实例response
- HttpServletResponse实例session
- HttpSession实例webRequest
- GrailsWebRequest实例
<% %>
语法,你当然可以使用这样的语法进行嵌套循环等等操作:
<html>
<body>
<% [1,2,3,4].each { num -> %>
<p><%="Hello ${num}!" %></p>
<%}%>
</body>
</html>
同样可以分支逻辑:
<html>
<body>
<% if(params.hello == 'true' )%>
<%="Hello!"%>
<% else %>
<%="Goodbye!"%>
</body>
</html>
import
指令允许在页面中导入类。然而,它却很少被使用,因为Groovy缺省导入和
GSP标签已经足够:
<% page import="java.awt.*" %>
GSP同样支持
contentType@ 指令
<% page contentType="text/json" %>
contentType@ָ令允许GSP使用其他的格式来渲染。
表达式
尽管GSP也支持<%= %>
语法,而且很早就介绍过,但在实际当中却很少应用,因为此用法主要是为ASP和 、JSP开发者所保留的。而GSP的表达式跟JSP EL表达式很相似的,跟Groovy GString的${expr}
用法也很像
<html>
<body>
Hello ${params.name}
</body>
</html>
尽管如此,跟JSP EL不同的是,你可以在
${..}
括号中使用Groovy表达式。
${..}
中的变量缺省情况下是
不被转义的,因此变量的任何HTML字符串内容被直接输出到页面,要减少这种Cross-site-scripting (XSS)攻击的风险,你可以设置
grails-app/conf/Config.groovy
中的
grails.views.default.codec
为HTML转化方式。
grails.views.default.codec='html'
其他可选的值是'none' (缺省值)和'base64'。
GSP标签
现在,JSP遗传下来的缺点已经被取消,下面的章节将涵盖GSP的内置标签,它是定义GSP页面最有利的方法。
所有GSP内置标签以前缀g:
开始。不像JSP,你不需要指定任何标签库的导入。假如,一个标签以g:
开始,它被自动认为是一个GSP标签。一个GPS标签的示例看起来像这样:
<g:example />
GSP标签同样可以拥有主体,像这样:
<g:example>
Hello world
</g:example>
表达式被传递给GSP标签属性,假如没有使用表达式,将被认为是一个String值:
<g:example attr="${new Date()}">
Hello world
</g:example>
Maps同样能被传递给GSP标签属性,通常使用一个命名参数样式语法:
<g:example attr="${new Date()}" attr2="[one:1, two:2, three:3]">
Hello world
</g:example>
注意,对于String类型属性值,你必须使用单引号:
<g:example attr="${new Date()}" attr2="[one:'one', two:'two']">
Hello world
</g:example>
变量和作用域
变量可以在GSP中使用 set标签来定义:
<g:set var="now" value="${new Date()}" />
这里,我们给GSP表达式结果赋予了一个名为
now
的变量 (简单的构建一个新的
java.util.Date
实体)。你也可以在
<g:set>
主体中定义一个变量:
<g:set var="myHTML">
Some re-usable code on: ${new Date()}
</g:set>
变量同样可以被放置于下列的范围内:
page
- 当前页面范围 (默认)request
- 当前请求范围flash
- flash作用域,因此它可以在下一次请求中有效session
- 用户session范围application
- 全局范围.
选择变量被放入的范围可以使用scope
属性
<g:set var="now" value="${new Date()}" scope="request" />
逻辑和迭代
GSP同样支持迭代逻辑标签,逻辑上通过使用 if, else 和 elseif来支持典型的分支情形。
g:if test="${session.role == 'admin'}">
<%-- show administrative functions --%>
</g:if>
<g:else>
<%-- show basic functions --%>
</g:else>
GSP用
each和
while 标签来处理迭代:
<g:each in="${[1,2,3]}" var="num">
<p>Number ${num}</p>
</g:each>
<g:set var="num" value="${1}" />
<g:while test="${num < 5 }">
<p>Number ${num++}</p>
</g:while>
搜索和过滤
假如你拥有对象集合,你经常需要使用一些方法来排序和过滤他们。GSP支持 findAll 和 grep来做这些工作。
Stephen King's Books:
<g:findAll in="${books}" expr="it.author == 'Stephen King'">
<p>Title: ${it.title}</p>
</g:findAll>
expr
属性包含了一个Groovy表达式,它可以被当作一个过滤器来使用。谈到过滤器,
grep标签通过类来完成与过滤器类似的工作:
<g:grep in="${books}" filter="NonFictionBooks.class">
<p>Title: ${it.title}</p>
</g:grep>
或者使用一个正则表达式:
<g:grep in="${books.title}" filter="~/.*?Groovy.*?/">
<p>Title: ${it}</p>
</g:grep>
上面的示例同样有趣,因为它使用了GPath.Groovy的GPath等同与XPath语言。实际上
books
集合是
Book
集合的实体。不过,假设每个
Book
拥有一个
title
,你可以使用表达式
books.title
来获取Book titles的list.
链接和资源
GSP还拥有特有的标签来帮助你管理连接到控制器和操作.link标签允许你指定控制器和操作配对的名字,并基于URL映射来自动完成连接。即使你去改变!
一些link的示例如下
<g:link action="show" id="1">Book 1</g:link>
<g:link action="show" id="${currentBook.id}">${currentBook.name}</g:link>
<g:link controller="book">Book Home</g:link>
<g:link controller="book" action="list">Book List</g:link>
<g:link url="[action:'list',controller:'book']">Book List</g:link>
<g:link action="list" params="[sort:'title',order:'asc',author:currentBook.author]">
Book List
</g:link>
表单和字段
GSP支持许多不同标签来帮助处理HTML表单和字段,最基础的是form标签,form
标签是一个控制器/操作所理解的正规的HTML表单标签版本。url
属性允许你指定映射到哪个控制器和操作:
<g:form name="myForm" url="[controller:'book',action:'list']">...</g:form>
我们创建个名为
myForm
的表单,它被提交到
BookController
的
list
操作。除此之外,适用于所有不同的HTML属性。
同构造简单的表单一样,GSP支持如下不同字段类型的定制:
- textField - 'text'类型输入字段
- checkBox - 'checkbox'类型输入字段
- radio - 'radio'类型输入字段
- hiddenField - 'hidden'类型输入字段
- select - 处理 HTML 选择框
上面的每一个都允许GSP表达式作为值:
<g:textField name="myField" value="${myValue}" />
GSP同样包含上面标签的扩张助手版本,比如
radioGroup (创建一组
radio 标签),
localeSelect,
currencySelect 和
timeZoneSelect (选择各自的地区区域, 货币 和时间区域).
多样的提交按钮
处理多样的提交按钮这样由来已久的问题,同样可以通过Grails的actionSubmit标签优雅的处理。它就像一个正规提交,但是,允许你指定一个可选的操作来提交。
<g:actionSubmit value="Some update label" action="update" />
标签作为方法调用
GSP标签和其他标签技术一个主要不同在于,来自控制器,标签库或者GSP 视图中的GPS标签可以被当作任意的正规标签或者当作方法被调用.
来自GSPs中的标签当作方法调用
当作为方法被调用时,标签的返回值被当作String实体直接被写入响应中。因此,示例中的createLinkTo能等同的看做方法调用:
Static Resource: ${createLinkTo(dir:"images", file:"logo.jpg")}
当你必须在一个属性内使用一个标签时是特别有用的
<img src="${createLinkTo(dir:'images', file:'logo.jpg')}" />
来自控制器(Controllers)和标签库的标签作为方法调用
你同样可以调用来自控制器和标签库的标签。标签可以不需要内部默认的 g:
namespace前缀来调用,并返回String结果:
def imageLocation = createLinkTo(dir:"images", file:"logo.jpg")
假如你有一个
custom namespace,你可以使用它的前缀来替换(例如,使用
FCK Editor plugin):
def editor = fck.editor()
视图和模板
和视图一样,Grails有模板的概念。模板有利于分隔出你的视图在可维护的块中,并与Layouts结合提供一个高度可重用机制来构建视图。
模板基础
Grails使用在一个视图名字前放置一个下划线来标识为一个模板的规约。例如,你可能有个位于grails-app/views/book/_bookTemplate.gsp
的模板处理渲染Books :
<div class="book" id="${book?.id}">
<div>Title: ${book?.title}</div>
<div>Author: ${book?.author?.name}</div>
</div>
为了渲染来自
grails-app/views/book
视图中的一个模板,你可以使用
render标签:
<g:render template="bookTemplate" model="[book:myBook]" />
注意,我们是怎么样使用render标签的
model
属性来使用传入的一个model。假如,你有多个
Book
实体,你同样可以使用render标签为每个
Book
渲染模板
<g:render template="bookTemplate" var="book" collection="${bookList}" />
共享模板
在早先的示例中,我们有一个特定于BookController
模板,它的视图位于 grails-app/views/book
。然而,你可能想横跨你的应用来共享模板。
既然这样,你可以把他们放置于grails-app/views视图根目录或者位于这个位置的任何子目录,然后在模板属性在模板名字之前使用一个/
来指明相对模板路径
<g:render template="/shared/mySharedTemplate" />
你也可以使用这个技术从任何视图或控制器(Controllers)来引用任何目录下的模板:
<g:render template="/book/bookTemplate" model="[book:myBook]" />