整理下Velocity使用方法,整理比较详细用例
1 Velocity基础语法
1.1 用户和开发人员参考文档
http://velocity.apache.org/engine/releases/velocity-1.7/developer-guide.html
1.2 注释
1.行级注释##
2.多行注释#* *#
1.3 变量定义
使用$开头的字符串是变量定义,例如$var1, $var2,
1.4 赋值
使用#set为变量赋值,例如
Java代码
- #set($var1 = 100)
- #set($str="foobar")
- #set($var2 = $var1)
- $var2 ##显示100
1. #set指令需要使用小括号将赋值语句括起来
2. #set语句后面不要加“;”,否则;将解析到页面上
3. #set是行级指令,不需要使用#end
1.5 {}含义
假如有一个Velocity变量,例如$abc, 那么$abcdef这种串如何表达它的含义,即变量$abc的值连接def,默认Velocity会认为$abcdef是一个变量,此时需要使用${abc}def来表达它的含义。
1.6 算术运算
1. 运算符: + - * / %
2. 使用#set语句执行算术运算操作
Java代码
- #set($a = 5)
- #set($b = 4)
- #set($c = 3)
- #set($d = 2)
- #set($e = 7)
- #set($a= $a+$b*$c/$d - 6%$e) ##5+4*3/2-6%7=5
- "Result:" $a
1.7 关系运算
> >= == <= <
1.8 逻辑运算
&& || !
1.9 条件判断
Java代码
- #set($var1 = 20)
- #if($va1 >= 100)
- $var1 is greater than or equals 100
- #elseif($va1 >= 50)
- $var1 is betwen [50, 100)
- #elseif($var1 >= 0)
- $var1 is between [0,50)
- #else
- $var1 is negative
- #end
1. #if是条件判断语句,#if/#else, #if/#elseif/#else 是if/else条件判断语句
2. if/elseif使用括号括起来
3. #if是块级指令,因此使用#end显示指定块级指令的结束
1.10 循环语句
Java代码
- #set($array = [1, "Two", 3,"Four"])
- #foreach($i in $array)
- <li>
- The $velocityCount element in the array is $i
- </li>
- #end
1. 数组定义类似于Javascript,用中括号[]括起来,以逗号分隔
2. $velocityCount是Velocity内置属性,用于指示当前循环的次数,从1开始计算,即第一次循环,它的值是1
3. #foreach in语句用于表示循环,
4. #foreach语句也是块级语句,需要使用#end来指明语句的结束
1.11 $!的含义
$!var1的含义是如果变量var1存在,则取其值,否则取空,即不显示,它等价于如下语句
Java代码
- #set($var1 = 100)
- $!var2 ##show nothing
- $!var1 ##show 100
- #if($var1)
- $var1
- #end
- #if($var2)
- #var2
- #end
1.12 #include指令
#include可以在vm中指定静态文件,这跟JSP的include标签的含义一样,例如
#include("staticHTML.html"),这个staticHTML.html
#include指令默认从classpath开始寻找文件??目前不确定!
1.13 Velocity资源加载器
在#include指令一节说到了include的文件到什么位置进行加载,这个位置与velocity资源加载的配置有关,常用的加载位置包括 webapp资源加载器,文件路径资源加载器,还有类路径记载器,在velocity.properties中,添加如下的配置项表示webapp资源加 载器,项目对于web项目的根开始算起
Java代码
- resource.loader=webapp
- webapp.resource.loader.class=org.apache.velocity.tools.view.WebappResourceLoader
- #relative to the web context, under the same parent directory with WEB-INF
- #that is, vm and WEB-INF are sibling folders
- webapp.resource.loader.path=/vm
其中的webapp是资源加载器的名称,/vm是web应用的根下面的vm目录,也就是说,vm目录和WEB-INF目录是平级的
Velocity是一个基于java的模板引擎。它允许任何人仅仅简单的使用模板语言来引用由java代码定义的对象。
当Velocity应用于web开发时,界面设计人员可以和java程序开发人员同步开发一个遵循MVC架构的web站点,也就是说,页面设计人员 可以只 关注页面的显示效果,而由java程序开发人员关注业务逻辑编码。Velocity将java代码从web页面中分离出来,这样为web站点的长期维护提 供了便利,同时也为我们在JSP和PHP之外又提供了一种可选的方案。
Velocity基本语法和使用:
1. "#"用来标识Velocity的脚本语句。
如:#set、#if 、#else、#foreach、#end、#include、#parse、#macro等。
2. "$"用来标识一个对象(或理解为PHP的变量)
如:、
user等。
3. "{}"用来明确标识Velocity变量,和普通模版字符串区分开来;
如:${user}‘s age 可以显示为 riqi's age。
4. "!"强制把不存在的变量显示为空白。
如:,假如对象为空,则模版中不显示该变量;如果缺少,则显示
msg字符串,这是我们不想要的结果。
5. 变量的定义和赋值。不需要指定变量的类型,类似弱类型语言PHP可以随意指定,在赋值后自动判定变量的类型,如:
#set($username="riqi") ##设置用户名
#set($age=26) ##设置年龄
6. 数组循环:
#foreach ($user in $users)
$!{user} $!{velocityCount} <br />
#end
可以是、或者,提供了得到循环次数的值:
velocityCount。
7. 语句注释:
单行注释:## 单行注释代码
多行注释:#* 多行注释代码 *#
8. 模版支持关系和逻辑操作符运算,如:&&、||、! 等
9. 宏定义:#macro ,类似PHP声明一个函数,其中有函数名称和参数列表。先定义再调用。
10. 终止命令:#stop,类似PHP的exit(); 停止执行模板引擎并返回。
11. 引入公共模版文件:#include与#parse,它们的差异是:
(1) 与#include不同的是,#parse只能指定单个对象。而#include可以有多个
如果您需要引入多个文件,可以用逗号分隔就行:
#include ("one.gif", "two.txt", "three.htm" )
在括号内可以是文件名,但是更多的时候是使用变量的:
#include ( “greetings.txt”, $seasonalstock )
(2) #include被引入文件的内容将不会通过模板引擎解析;
而#parse引入的文件内容Velocity将解析其中的velocity语法并移交给模板,意思就是说相当与把引入的文件copy到文件中。
#parse是可以递归调用的。
12. 转义字符'\'.
这个和其它语言没有差异,假如:那么,表示输出
user字符串,\\$user表示输出\riqi。
13. Velocity内置了一部分java对象 如:、
response、$session等,在vm模版里可以直接调用。
------------------------------------------------------------------------------------
细节整理:
1. Velocity判断某个变量是否为空的方式:
1 |
#if($!变量名)……#else……#end |
或者:
1 |
#if("" == $!varName)……#else……#end |
2 Velocity与Java互操作
Velocity出现的目的用于简化基于MVC的web应用开发,用于替代JSP标签技术,那么Velocity如何访问Java代码.本篇继续以Velocity三http://bit1129.iteye.com/blog/2106142中的例子为基础,
2.1 POJO
Java代码
- package com.tom.servlets;
- public class User {
- private String name;
- private String passwd;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getPasswd() {
- return passwd;
- }
- public void setPasswd(String passwd) {
- this.passwd = passwd;
- }
- }
2.2 Service
Java代码
- package com.tom.servlets;
- public class UserService {
- public User get(String userId) {
- User user = new User();
- user.setName("tom");
- user.setPasswd("tom_pwd");
- return user;
- }
- public User get(Long userId) {
- User user = new User();
- user.setName("Jack");
- user.setPasswd("Jack");
- return user;
- }
- public void save() {//用于测试,vm是否可以调用无参数的方法
- System.out.println("save is called");
- }
- }
2.3 Servlet代码
Java代码
- package com.tom.servlets;
- import org.apache.velocity.Template;
- import org.apache.velocity.context.Context;
- import org.apache.velocity.tools.view.VelocityViewServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class TestVelocityViewServlet extends VelocityViewServlet {
- @Override
- protected Template handleRequest(HttpServletRequest request, HttpServletResponse response, Context ctx) {
- UserService userService = new UserService();
- ctx.put("userService" , userService);//把userService对象设置到Context中
- return getTemplate("obj.vm");
- }
- }
2.4 vm代码
Html代码
- <!--obj.vm-->
- <html>
- <body>
- <p>$userService</p> ##call userService's toString method
- #set($user = $userService.get(0)) ##When call the java method on its object, only string typed parameters can be accepted
- <p>$user.name</p> ##print #$user.name as it is, because $user can't be resolved
- <p>$user.getName()</p> ##Equivalent with $user.name
- #set($user = $userService.get("0"))
- <p>$user.name</p> ##print $$user.name as it is, because $user can't be resolved
- <p>$user.getName()</p> ##Equivalent with $user.name
- <p>$user.save()</p> ##$user.save can't be resolved,so vm can't resolve method that takes no parameter
- </body>
- </html>
2.5 运行结果
com.tom.servlets.UserService@48b4721b
$user.name
$user.getName()
tom
tom
$user.save()
2.6 总结
1.可以通过Velocity将Java的对象注入到Context中,这样在vm中可以获得这个注入的Java对象,例子中调用了这个Java对象的toString方法
2.在vm中,仅仅能调用Java对象的带有String类型参数的方法,这是非性常巨大的局限,因为在vm中,没法像在JSP中通过<%%>创建Java对象,然后把它作为参数调用Java的方法
3.对于setter和getter,可以直接使用属性进行方法,例如$user.getName和$user.name是等价的,不管User类是否定义了name属性(比如把User类中的属性name改名为xname,getName和setName方法名不变)
4.$user.save()不能正确解析,也就是说,vm只能调用Java对象带String类型参数的方法(POJO的get方法除外)
3 脱离servlet使用velocity
Java代码
- package com.tom.velocity;
- import java.io.InputStream;
- import java.io.StringWriter;
- import java.util.Properties;
- import org.apache.velocity.Template;
- import org.apache.velocity.VelocityContext;
- import org.apache.velocity.app.VelocityEngine;
- public class HelloVelocity {
- public static void main(String[] args) throws Exception {
- //实例化并初始化Velocity模板引擎
- VelocityEngine ve = new VelocityEngine();
- Properties p = new Properties();
- InputStream in = HelloVelocity.class.getClassLoader().getResourceAsStream("velocity.properties");
- p.load(in);
- ve.init(p);
- //从指定目录下加载自定的vm文件
- Template t = ve.getTemplate("vm/hello.vm");
- //创建Velocity上下文环境,用于在vm和Java传值
- VelocityContext context = new VelocityContext();
- context.put("name", "tom");
- context.put("job", "code-farmer");
- //将模板序列化为字符串文档,进行打印
- StringWriter writer = new StringWriter();
- t.merge(context, writer);
- //将模板引擎解析的结果打印输出
- System.out.println(writer.toString());
- //输出
- /*
- <p>name: tom</p>
- <p>job: code-farmer</p>
- */
- }
- }
3.1 velocity.properties文件
存放在classpath根目录下,内容:
Java代码
- resource.loader=class
- #Why ClasspathResourceLoader search the vm in the root directory of classpath
- #This means, <class.resource.loader.path> doesn't take effect
- class.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
- class.resource.loader.path=vm
3.2 hello.vm文件
存放在{classpath根目录}/vm目录下。
Java代码
- <p>name: $name</p>
- <p>job: $job</p>
3.3 java中使用详细实例
3.3.1 模板内容
<?xml version="1.0" encoding="utf-8"?>
<T24 xmlns="http://www.temenos.com/T24/OFSML/130" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.temenos.com/T24/OFSML/130 ofsml13.xsd">
<ofsmlHeader>
<requestId>$_utils.uuid()$ofsRequest.getTxCode()</requestId>
<correlationId/>
</ofsmlHeader>
<serviceRequest>
<securityContext>
<userName>$ofsRequest.getName()</userName>
<password>$ofsRequest.getPassword()</password>
<company>$ofsRequest.getCompany()</company>
</securityContext>
<ofsStandardEnquiry name="$ofsRequest.getEnquiryName()">
#set($struct = $ofsRequest.getStruct)
#foreach ($item in $ofsRequest.getMessageData())
#if($_tools.isEmpty($struct) || $_tools.isNotEmpty($struct.get($item.getName())))
<selectionCriteria operand="$item.getOperator()">
<fieldName>$item.getName()</fieldName>
<value>#foreach($vItem in $item.getValue())$vItem #end</value>
</selectionCriteria>
#end
#end
</ofsStandardEnquiry>
</serviceRequest>
</T24>
3.3.2 重点部分java代码
// 组合请求消息报文对象
OFSEnquiryRequest ofsRequest = new OFSEnquiryRequest();
ofsRequest.setHeader(msgType + SPLIT_ROW + txCode);
ofsRequest.setName(name);
ofsRequest.setPassword(password);
ofsRequest.setCompany(company);
ofsRequest.setEnquiryName((String) msgHead.get("enquiryName"));
ofsRequest.setStruct(struct);
ofsRequest.setTxCode(txCode);
if (null != msgBody && msgBody.containsKey("messageData")) {
ofsRequest.setMessageData((List<OFSEnquiryReqItem>) msgBody.get("messageData"));
}
// 根据模板组合请求xml内容
VelocityContext ctx = new VelocityContext();
ctx.put("_tools", Tools.getInstance());
ctx.put("_utils", VelocityUtil.getInstance());
ctx.put("ofsRequest", ofsRequest);
String ofsmlEqyXml = "";
try {
// 变量REQ中保存了上面的模板内容
ofsmlEqyXml = VelocityHelper.getText(REQ, ctx);
} catch (Exception e) {
}
4.Velocity模板优缺点
对于大部分的应用来说,使用 FreeMarker 比 Velocity 更简单,因为 Velocity 还必须编写一些自定义的toolbox类以及一遍遍重复的编写一些比较通用的模版代码,因此也就丧失了刚开始开发时更多的宝贵时间。另外使用工具类和变通的方法在模版引擎中似乎不是一个非常有效的做法。同时,Velocity 的做法使得在Velocity的模版中大量的跟 Java 对象进行交互,这违反了简单的原则,尽管你也可以将代码转入控制器中实现。当然,如果你像使用 Velocity 一样来使用 FreeMarker ,那么 FreeMarker 也可以跟 Velocity 一样简单。
Velocity 一个优于 FreeMarker 的地方在于它有很广泛的第三方支持以及一个非常庞大的用户社区,你可以通过这个社区获得到很多的帮助,相反的 FreeMarker 在这方面要差很多。当然,也有越来越多的第三方软件开始在支持 FreeMarker 。
velocity性能比freemarker好很多,应该是最好的,又看到说性能超过jsp。