像 Java Server Pages JSP) 一样,GSP支持定制tag库的概念.不同于JSP,Grails标签库机制是简单的,优雅的,在运行时完全可重载的.
创建一个标签库是相当简单的,创建一个以规约TagLib
结尾的一个Groovy类,并把它放置于grails-app/taglib
目录里:
class SimpleTagLib {}
现在,为了创建一个标签,简单的创建属性并赋值一个带有两个参数的代码块:标签属性和主体内容:
class SimpleTagLib { def simple = { attrs, body ->} }
attrs
属性是一个简单的标签属性map,同时body
是另一可调用的代码块,它返回主体内容:
class SimpleTagLib { def emoticon = { attrs, body -> out << body() << attrs.happy == 'true' ? " :-)" : " :-(" } }
正如以上所显示的,这里有个隐式的out
变量,它引用了输出Writer
,可以用来附加内容到响应中. 然后,你可以在你的GSP内简单的引用这个标签而不需要任何导入:
<g:emoticon happy="true">Hi John</g:emoticon>
在标签库的作用域中包含了一些预先定义好的变量:
actionName
- 当前执行的操作(action)名 controllerName
- 当前执行的控制器(controller)名 flash
- The flash 对象 grailsApplication
- The GrailsApplication实体 out
- The response writer for writing to the output stream pageScope
- pageScope 对象引用,用于GSP渲染(即. binding) params
- The params 对象,用于取得请求参数 pluginContextPath
- 插件上下文路径 ,它包含标签库 request
- HttpServletRequest实体 response
- HttpServletResponse实体 servletContext
- javax.servlet.ServletContext实体 session
- HttpSession实体
作为演示,早先的示例只不过是写了个没有主体只有输出内容的简单标签。另一个示例是一个 dateFormat
样式标签:
def dateFormat = { attrs, body ->
out << new java.text.SimpleDateFormat(attrs.format).format(attrs.date)
}
上面使用了Java的SimpleDateFormat
类来格式化一个date,然后把它写入响应。随后,这个标签能像下列这样在GSP中使用:
<g:dateFormat format="dd-MM-yyyy" date="${new Date()}" />
有时。你需要用简单的标签把HTML标签(mark-up)写入到响应中。一个方法是直接嵌套内容:
def formatBook = { attrs, body -> out << "<div id="${attrs.book.id}">" out << "Title : ${attrs.book.title}" out << "</div>" }
虽然,这个方法可能很诱人,但不是非常的简洁。一个更好的方法将是复用render标签:
def formatBook = { attrs, body ->
out << render(template:"bookTemplate", model:[book:attrs.book])
}
然后,这个单独的GSP模板做了实际的渲染工作.
一旦一组条件满足,你同样可以在标签的主体中创建仅仅用来输出的逻辑标签。一个这样的例子可能是一组安全标签:
def isAdmin = { attrs, body -> def user = attrs['user'] if(user != null && checkUserPrivs(user)) { out << body() } }
上面的标签检查用户是否为管理人员,如果他/她有正确设置的访问权限只输出主体内容:
<g:isAdmin user="${myUser}"> // some restricted content </g:isAdmin>
迭代标签同样普通,因为你可以多次调用主体:
def repeat = { attrs, body -> attrs.times?.toInteger().times { num -> out << body(num) } }
在这个示例中,我们检查一个times
属性,假如存在,把它转换为一个数字,然后使用Groovy的times
方法:
<g:repeat times="3"> <p>Repeat this 3 times! Current repeat = ${it}</p> </g:repeat>
注意,我们是怎么样在这个示例中使用隐式的it
变量来引用当前的数字。这个过程是因为在迭代内部我们调用了传递进入当前值的主体:
out << body(num)
那个值然后被作为默认的it
变量传递给标签,然而,假如你有嵌套标签便会导致冲突,因此,你将可能替换主体使用的变量名:
def repeat = { attrs, body -> def var = attrs.var ? attrs.var : "num" attrs.times?.toInteger().times { num -> out << body((var):num) } }
这里,我们检查是否存在一个var
属性,如果存在的话,将其作为body调用的参数:
out << body((var):num)
注意,变量名围绕的圆括号的使用.假如你省略,Groovy会认为你使用了一个String关键字,而不是引用这个变量它自己.
现在,我们可以改变这个标签的使用方法,如下:
<g:repeat times="3" var="j"> <p>Repeat this 3 times! Current repeat = ${j}</p> </g:repeat>
注意,我们是怎么样使用var
属性来定义j
变量名,随后,我们可能在标签主体类引用这个变量.
默认情况下,标签被添加到默认的Grails命名空间,并在GSP页面中和 g:
前缀一起使用。然而,你可以指定一个不同的命名空间,通过在你的 TagLib
类中添加一个静态属性:
class SimpleTagLib { static namespace = "my"def example = { attrs -> … } }
这里,我们指定了一个命名空间
my
,因此,稍后在GPS页面中标签库中的标签引用会像这样:
<my:example name="..." />
前缀和静态的命名空间
属性值一样.命名空间对于插件特别有用.
命名空间内的标签可以作为方法调用,使用命名空间作为前缀来执行方法调用:
out << my.example(name:"foo")
可用于GSP,控制器或者标签库.
除了GSP提供的简单标签库机制, 你也可以在GSP中使用JSP标签.通过taglib
指令来简单声明你需要的JSP标签:
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
随后,你可以想任何其他标签一样来使用它:
<fmt:formatNumber value="${10}" pattern=".00"/>
额外的好处是,你可以把JSP标签当方法调用 :
${fmt.formatNumber(value:10, pattern:".00")}