Velocity学习2之Context

1.The Basics


'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 中每次都要保存大量新的信息.






















  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值