Velocity学习2之Context
1.The Basics'context' 是Velocity 中的一个核心概念, 这是一个从系统的”数据容器(a container of data)”引出的一个常见概念. 这里的context 在java 程序层和模板视图层(template layer ( or the designer))之间扮演着一个”数据对象传送者”'(carrier')的角色.做为程序员,你可以将你程
'context' 是Velocity 中的一个核心概念, 这是一个从系统的”数据容器(a container of data)”引出的一个常见概念. 这里的context 在java 程序层和模板视图层(template layer ( or the designer))之间扮演着一个”数据对象传送者”'(carrier')的角色.
做为程序员,你可以将你程序生成的不同类型的数据对象放入context 中,对于视图设计来说,这些对象(包含它们的数据域和命令)将在模板元素中被引用到(references)。一般来说,你将和视图设计者一起决定应用需要哪些数据,可以说,你放入context 中的数据对象在这里成为一种”API”,由视图设计者在模板中来访问.因此,在向context 中决定放放哪些数据对象时,程序的设计者需要仔细分析视图表现所需的数据内容。
虽然Velocity 中你可以创建自己的Context 类来支持一些个性化的应用(比如,一个访问,保存LDAPServer 服务的context),你可以实现VelocityContext 这个己封装较为完务的基类。VelocityContext 对象基本上可满足大多的应用, 我们强烈建议你除非在特别的情况下,否则不要创建自己的Context 实现!
VelocityContext 用法十分简单,类似于Hashtable class.下面是这个接口提供的两个基本用法:
public Object put(String key, Object value);
public Object get(String key);
很像Hashtable 吧,这里的value 必须是一个java.lang.Object类(不能是原始类型,像int,boolean), 也不能是null 值. 原始类型(Fundamental types like int or float)必须被包装为一个适当对应的Object 型.
2.在模板中用#foreach 指令支持迭代对象
在放入context 前,你对对象有着全面的操作自由. 但就像所有的自由一样, 你必须遵守一些规则,承担一些责任,因此,你必须理解Velocity 是如何使用对象的,Velocity 的VTL 支持多种类型的集合类型(collection types) 使用#foreach().
Object [] 一般对象数组. Velocity 将内功能会将它包装成功之为一个实现Iterator interface 对象, 这个转换是不需要程序员或视图设计者参与.
java.util.Collection :Velocity 会使用他们的标准iterator() 得到一个可以迭代中使用的Iterator 对象,如果你使用自己的实现了Collection interface 的对象,要确保它的iterator()命令返回一个可用的Iterator.
java.util.Map 接口对象,Velocity 使用其顶层接口的values() 命令得到一个实现Collectioninterface 的对象, 应用其iterator()再返回一个Iterator.
java.util.Iterator 使用特别注意: 如果一个Iterator 对象被放置到context 中,当在模板中有多个#foreach()指令中,这些#foreach() 将顺序执行,如果第一个调用失败,后面的将阻塞且不能重置.
java.util.Enumeration USE WITH CAUTION : 如同java.util.Iterator 一样的道理,Velocity将使用的是一个不能重置('non-resettablity')或者说一个final 型的对象.因此,仅当在不得己的情况下,Iterator and Enumeration 对象才有必要放入context 中---也许你有更好的办法不使用他们.
例子1:
vm文件内容:
hello
#foreach($name in $names)
$name
#end
#foreach($name in $citys)
$name
#end
java代码:
public class Context {
public static void main(String[] args) throws Exception {
Velocity.init();
VelocityContext ctx = new VelocityContext();
Vector v = new Vector();
v.addElement("Shanghai");
v.addElement("Beijing");
Object[] objs = {"word","世界"};
ctx.put("names", objs);
ctx.put("citys", v);
Template tem = null;
tem = Velocity.getTemplate("myTemplate.vm");
StringWriter writer = new StringWriter();
tem.merge(ctx, writer);
System.out.println(writer.toString());
/* 输出流输出到文件*/
PrintWriter filewriter = new PrintWriter(new FileOutputStream("E:/i.html"), true);
filewriter.print(writer.toString());
filewriter.close();
}
}
输出文件内容:
hello word 世界 Shanghai Beijing
3.Context Chaining
另外一个新引入的概念是context chaining.有时也叫做context wrapping(有点类似与servlet 中的chain), 这个高级特性让你可以连结多个独立的Velocity 的contexts,以便在template 中使用.
vm文件内容:
hello $name $city
java代码:
public class Context {
public static void main(String[] args) throws Exception {
Velocity.init();
VelocityContext ctx1 = new VelocityContext();
ctx1.put("name", "world");
ctx1.put("city", "GuangZhou");
VelocityContext ctx2 = new VelocityContext( ctx1 );
ctx2.put("name", "世界");
Template tem = null;
tem = Velocity.getTemplate("myTemplate.vm");
StringWriter writer = new StringWriter();
tem.merge(ctx2, writer);
System.out.println(writer.toString());
/* 输出流输出到文件*/
PrintWriter filewriter = new PrintWriter(new FileOutputStream("E:/i.html"), true);
filewriter.print(writer.toString());
filewriter.close();
}
}
可以看到
VelocityContext ctx2 = new VelocityContext( ctx1 );
context2 做为context1 的chains. 这意味着你在模板中可以使用放入这两个context 中的任何一个对象, 当两个context 中有相同的key 中,在模板中输出时,将会输出最后一个key 的值,如上例key 为name的值将输出为"世界".
其实,在上例中 context1 中的string "word" 依然可以通过context1.get("name")方法得到. 但在上例中,模板中引用'$name' 将会返回'世界', 而且模板不能再访问到context1 中的'world'.
另外要注意的是,当你尝试在模板中加入信息,比如使用#set()声明,这将对所己输出的模板产生影响.
4.模板中的己创建对象
Java 代码中的数据对象与模板交互有两种常见方式:
模板设计者从模板中执行程序员放入到context 中的java 对象的命令:
#set($myarr = ["a","b","c"] )
$foo.bar( $myarr )
当模板加入一个对象到context 中,模板合并输出后,java 代码将可以访问这些对象.
#set($myarr = ["a","b","c"] )
#set( $foo = 1 )
#set( $bar = "bar")
5.Context 对象的其它用法
每一个VelocityContext(或任意源自AbstractContext)的对象,都是一个封装好指定规则的的存储节
点,对于一般开发都来说,只需使用就是.但这里还有一些你应知道的特性:
考虑以下情况:
你的模板重复使用VelocityContext object.
Template caching is off.
反复调用getTemplate() 命令.
这都有可能引起VelocityContext 的内存泄露( 'leak' memory )---当它汇集过多的数据对象时,因此
强烈建议你做到以下几点:
在每个模板渲染过种中(template render process)创建一个新的VelocityContext. 这会防止
过多的cache data. 当需要重用一个VelocityContext 因为它内部己放置了数据对象, 你只需
要像这样简单的包装一下:VelocityContext useThis = new VelocityContext( populatedVC );
具体可以参看Context chaining 获取更多信息.
打开模板的caching 功能. 以防止重复解析模板,当然,这会要求服务器有更高的性能.
在迭代操作时,要重用模板对象. 这样将不会对Velocity 造成过大压力, 如果缓存关闭, 就需要每次都
读取和解析模板, 导致VelocityContext 中每次都要保存大量新的信息.
更多推荐
所有评论(0)