精通 Grails: 用 Groovy 服务器页面(GSP)改变视图
自定义标记库
虽然标准 Grails 标记很有帮助,但是最终会遇到需要自定义标记的情况。许多资深 Java 开发人员(包括我自己)公开表示,“自定义 TagLib 是合适的架构性解决方案。”,然后却偷偷地编写 scriptlet,以为别人看不到。编写自定义 JSP TagLib 需要的工作太多,所以难以抵抗 scriptlet 的诱惑。scriptlet 并不是正确的方法,但不幸的是,它是一种容易实现的方法。
Scriptlet 破坏了 HTML 基于标记的范式,将原始代码直接引入视图。错误的并不是代码本身,而是它们缺少封装和重用的潜力。重用 Scriptlet 的惟一方式就是 “复制-粘贴”。这导致 bug、代码膨胀,并严重违背了 DRY 原则。更不用说 Scriptlet 在可测试性方面的匮乏了。
这就是说,我必须坦白,随着开发期限越来越紧迫,我写的 JSP scriptlet 的比例也相当大。JPS 标准标记库(JSP Standard Tag Library,JSTL)在这方面帮助了我很多,但是编写我自己的自定义 JSP 标记则完全是另一回事。在我用 Java 代码编写自定义 JSP 标记、编译标记,并将大量时间浪费在将标记库描述符(Tag Library Descriptor,TLD)设置为正确的格式和位置时,我已经完全忘记了当初编写这个标记的理由是什么。编写测试来验证我的新 JSP 标记是否正确也同样麻烦 — 只能说我的出发点是好的。
对比之下,用 Grails 编写自定义 TagLibs 简直就是举手之劳。Grails 框架使得做正确的事(包括编写测试)变得很容易。例如,我经常需要在 Web 页面底部加上标准的版权声明。版权声明应该是这样的: © 2002 - 2008, FakeCo Inc. All Rights Reserved.。问题在于,我希望第二个年份总是当前的年份。清单 6 显示了用 scriptlet 如何完成这个任务:
清单 6. 用 scriptlet 完成的版权声明
© 2002 - ${Calendar.getInstance().get(Calendar.YEAR)},
FakeCo Inc. All Rights Reserved.
</div>
既然知道了如何处理当前年份,那么下面就要创建一个执行同样任务的自定义标记。请输入 grails create-tag-lib Date,这会创建两个文件:grails-app/taglib/DateTagLib.groovy(TagLib)和 grails-app/test/integration/DateTagLibTests.groovy(测试)。将清单 7 中的代码添加到 DateTagLib.groovy:
清单 7.简单的自定义 Grails 标记
def thisYear = {
out << Calendar.getInstance().get(Calendar.YEAR)
}
}
清单 7 创建一个
清单 8.使用自定义标记的版权声明
© 2002 - <thisYear />, FakeCo Inc. All Rights Reserved.
</div>
您可能以为这就完成了。非常抱歉,这只完成了一半。