Velocity学习2之Context

/ 后端 / 无站内评论 / 325浏览
转自:http://blog.csdn.net/anders_zhuo/article/details/9444145

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文件内容:

[java] view plain copy
  1. hello   
  2. #foreach($name in $names)  
  3. $name  
  4. #end  
  5.   
  6. #foreach($name in $citys)  
  7. $name  
  8. #end  

java代码:

[java] view plain copy
  1. public class Context {  
  2.     public static void main(String[] args) throws Exception {  
  3.         Velocity.init();  
  4.           
  5.         VelocityContext ctx = new VelocityContext();  
  6.         Vector v = new Vector();  
  7.         v.addElement("Shanghai");  
  8.         v.addElement("Beijing");  
  9.           
  10.         Object[] objs = {"word","世界"};  
  11.           
  12.         ctx.put("names", objs);  
  13.         ctx.put("citys", v);  
  14.           
  15.         Template tem = null;  
  16.         tem = Velocity.getTemplate("myTemplate.vm");  
  17.         StringWriter writer = new StringWriter();  
  18.         tem.merge(ctx, writer);  
  19.           
  20.           
  21.         System.out.println(writer.toString());  
  22.                 /* 输出流输出到文件*/  
  23.         PrintWriter filewriter = new PrintWriter(new FileOutputStream("E:/i.html"), true);   
  24.                 filewriter.print(writer.toString());  
  25.                 filewriter.close();  
  26.     }  
  27. }  

输出文件内容:

hello word 世界 Shanghai Beijing


3.Context Chaining
另外一个新引入的概念是context chaining.有时也叫做context wrapping(有点类似与servlet 中的chain), 这个高级特性让你可以连结多个独立的Velocity 的contexts,以便在template 中使用.

vm文件内容:

hello   $name    $city

java代码:

[java] view plain copy
  1. public class Context {  
  2.     public static void main(String[] args) throws Exception {  
  3.         Velocity.init();  
  4.           
  5.         VelocityContext ctx1 = new VelocityContext();  
  6.           
  7.         ctx1.put("name""world");  
  8.         ctx1.put("city""GuangZhou");  
  9.           
  10.         VelocityContext ctx2 = new VelocityContext( ctx1 );  
  11.         ctx2.put("name""世界");  
  12.           
  13.         Template tem = null;  
  14.         tem = Velocity.getTemplate("myTemplate.vm");  
  15.         StringWriter writer = new StringWriter();  
  16.         tem.merge(ctx2, writer);  
  17.           
  18.           
  19.         System.out.println(writer.toString());  
  20.                 /* 输出流输出到文件*/  
  21.         PrintWriter filewriter = new PrintWriter(new FileOutputStream("E:/i.html"), true);   
  22.                 filewriter.print(writer.toString());  
  23.                 filewriter.close();  
  24.     }  
  25. }  

可以看到 
[java] view plain copy
  1. VelocityContext ctx2 = new VelocityContext( ctx1 );  
[java] view plain copy
  1. <span style="color:#ff0000;"><strong>context2 做为context1 的chains. 这意味着你在模板中可以使用放入这两个context 中的任何一个对象, 当两个context 中有相同的key 中,在模板中输出时,将会输出最后一个key 的值,如上例key 为name的值将输出为"世界".</strong></span>  
  2. <strong>其实,在上例中 context1 中的string "word" 依然可以通过context1.get("name")方法得到. 但在上例中,模板中引用'$name' 将会返回'世界', 而且模板不能再访问到context1 中的'world'.</strong>  
[java] view plain copy
  1. 另外要注意的是,当你尝试在模板中加入信息,比如使用#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 中每次都要保存大量新的信息.

召唤蕾姆
琼ICP备18000156号

鄂公网安备 42011502000211号