提起模板,在 Java 领域中无疑会让人想起 Velocity 和 FreeMarker,可也不要忽略了,和我们最早打交道的 JSP 其实也是一种模板。模板一般都用来作为数据显示分离的显示部分,即 MV 的 V。比如说我目前在 Web 展示和发送邮件时较多的用到模板。通常模板用占位符创建的一个文本,或者串文本、输入流等。这些占位符可以用自己的流程控制代码,所以相应的就有的各种模板语言,例如 VTL(Velocity Template Language)、FTL(FreeMarker Template Language)、自然 JSP 也有算上。
有了模板,再把模型数据和模板进行归并就能得到我们真正想要的数据展现了,这当中的工作就是叫做模板引擎的干的。Groovy 中包含了抽象的 groovy.text.TemplateEngine 类和 groovy.text.Template 接口。可见 Groovy 表现的很开放,它们使得将任何模板引擎插入到 Groovy 中成为可能,比如 Velocity 或者 FreeMarker 引擎,可惜现在还没有。
查看 groovy.text 包 http://groovy.codehaus.org/api/groovy/text/package-frame.html,我们可以看到 Groovy(当前版本 1.6-beta-1) 自己提供了GStringTemplateEngine、SimpleTemplateEngine、XmlTemplateEngine 三个模板引擎实现。我们在本篇介绍的是 SimplateTemplateEngine 的实现,其他两个引擎实现的应用留给读者自己研究。
groovy.text.SimpleTemplateEngine 这个引擎提供了类似于 JSP 2.0 的语法,并支持嵌入到模板中的下列表达式:
·<% statements %> -- 执行任何有效的 Groovy 语句
·<%=expression%> -- 将一个 Groovy 表达式的值嵌入到模板中
·${expression} -- 将一个 Groovy 表达式的值嵌入到模板中的另一种写法
下面我们用个完整的例子来说明 SimpleTemplateEngine 的用法,熟悉 Velocity 的朋友可以进行对比来理解。笔者之前写过一篇 Velocity 的入门的文章:掌握一种Java模板技术 -- Velocity,可请参考。
首先创建模板文件 userinfo.template
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<html> <head><title><%=title%></title></head> <body> <table border="1"> <tr><td>姓名</td><td>性别</td></tr> <% users.each{user-> out. println "<tr><td>${user.name}</td><td>${user.gender}</td></tr>" } %> </table> ${footer} </body> </html> |
在这个模板文件中,我们用到了前面提到的三种语法。因为下面的代码是通过 File 形式从当前目录被 TemplateEngine 加载的,所以这个模板文件应该放到 System.getProperty("user.dir") 所在的目录。其他时候要根据 TemplateEngine.createTemplate() 的参数来决定模板文件安放的位置。
然而是使用模板的 Groovy 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import groovy.text.Template import groovy.text.SimpleTemplateEngine import groovy.text.TemplateEngine TemplateEngine engine = new SimpleTemplateEngine() Template template = engine.createTemplate(new File("userinfo.template")) //声明要绑定(或者叫合并)到模板的一个 Map 对象 users = [[name:"Unmi",gender:"male"],[name:"hy",gender:"female"]] //把模型数据归并到模板中,通过 Map 来传递参数 Writable result = template.make(title:"显示用户信息",users:users,footer:"©Made by Unmi") //把归并后的结果输出来控制台 result.writeTo(new PrintWriter(System.out)) //如果是作为一个 Groovylet writeTo() 语句就可以写成 result.writeTo(out) //out 是 Groovlet 的内置变量 //或者不用上面的 writeTo() 方法,直接 toString() 能得到一样的结果 //print result.toString() //再干练点就是 print result |
对上面的代码要加以说明一下了:
TemplateEngineEngine 抽象类的 createTemplate() 可接受 File、URL、String 或 Reader 参数,这就意味着我们的模板可以表现为多种形式,而不仅仅是一个文件模板。
要绑定(或者叫归并) 到模板的数据是在 Template.make(Map map) 中通过 Map 参数传递过去的。
这里的 TemplateEngine.createTemplate() 就相当于 Velocity 的 VelocityEngine.getTemplate() 或 Velocity.getTemplate() 方法,Velocity 的这两个方法也是可以接受多种类型参数的。
Template.make(Map map) 和紧接着的 Writable.writeTo(Writer writer) 方法这两加起来就相当于 Velocity 的 Template.merge(VelocityContext context, Writer writer) 方法。
最后,看看上面程序执行的结果
执行后在控制台输出如下信息:
<html>
<head><title>显示用户信息</title></head>
<body>
<table>
<tr><td>姓名</td><td>性别</td></tr>
<tr><td>Unmi</td><td>male</td></tr>
<tr><td>hy</td><td>female</td></tr>
</table>
©Made by Unmi
</body>
</html>
对了,我这里有意在模板中用的是 HTML 格式,也就很明显,我们能很好的把 Groovy 模板技术运用到 Groovlet 中,如此可以大大简化 Groovlet 的开发。参看 Unmi 学习 Groovy 之 Groovlet。真要说呢,用 Groovy 模板来简化 Groovlet 开发还不够,后面还有 GroovyMarkup-MarkupBuilder 可以用。真正的终极目标应该在 Grails 的应用,本人对 Grails 基本还没什么了解。
参考:1. 《Scripting in Java Language, Frameworks, and Patterns》 Chaper 5
本文链接 https://yanbin.blog/unmi-study-groovy-templat/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。