概念
velocity是apache的子項目,官網http://velocity.apache.org/,類似於freemarker和jsp,是模板語言。
基本配置:
web工程中:
1、引入jar包:
2、web.xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>velocity_web_test</display-name>
<servlet>
<servlet-name>velocityView</servlet-name>
<servlet-class>org.apache.velocity.tools.view.VelocityViewServlet</servlet-class>
<load-on-startup>10</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>velocityView</servlet-name>
<url-pattern>*.vm</url-pattern>
</servlet-mapping>
</web-app>
其中配置了velocity的VelocityViewServlet,攔截*.vm請求。
3、寫一個vm文件,如test.vm
<html>
<head></head>
<body>
<table>
#set( $treeList = ["pine", "oak", "maple", "redwood"])
<tr><td>Tree Name</td></tr>
#foreach ($name in $treeList)
<tr>
<td>
<b><font color="GREEN">$name</font></b> is a big tree!
</td>
</tr>
#end
</table>
</body>
</html>
訪問結果:
表示已經成功。
velocity使用的語言成為VTL語言,類似於freemark的ftl。
servlet中使用velocity配置:
只用在自己的servlet中繼承基本配置中的VelocityViewServlet即可:
如:
VelocityServlet.java:
package com.test;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.velocity.Template;
import org.apache.velocity.context.Context;
import org.apache.velocity.tools.view.VelocityViewServlet;
/**
* 測試velocity的servlet
*/
public class VelocityServlet extends VelocityViewServlet {
private static final long serialVersionUID = 1L;
@Override
protected Template handleRequest(HttpServletRequest request, HttpServletResponse response, Context ctx) {
ctx.put("username", "anders");
return getTemplate("test.vm");
}
@Override
protected void setContentType(HttpServletRequest request, HttpServletResponse response) {
response.setContentType("text/html;charset=utf-8");
}
}
然后web.xml配置servlet:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>velocity_web_test</display-name>
<servlet>
<servlet-name>VelocityServlet</servlet-name>
<servlet-class>com.test.VelocityServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>VelocityServlet</servlet-name>
<url-pattern>/VelocityServlet</url-pattern>
</servlet-mapping>
</web-app>
test.vm:
<html>
<head></head>
<body>
hello,$username
</body>
</html>
訪問servlet(注意不要直接訪問vm),如:http://localhost/velocity_web_test/VelocityServlet
顯示:
hello, anders
在servlet的handleRequest方法中即可為vm頁面設置需要顯示的變量
基本用法
設置變量,取變量
#set($a="abc")
hello,$a
顯示
hello,abc
#后面一般接命令,$后面一般接變量
#set($a="abc")表示設置變量a為abc字符串
$a表示顯示變量a的值,所以就是:hello,abc
例子:
$data.setUser("jon")
##等同於
#set( $data.User = "jon" )
注釋
單行注釋:
## 單行注釋
多行注釋:
#*
多行1
多行2
*#
取值的方式
取值也叫作引用。
變量命名規則:字母開頭,后面可以是字母、數字、下划線、中划線
取值跟jstl類似,如:
${username}
${user.userName}
還可以直接執行java的方法,如:
<body>
username1: ${user.getUserName()}<br/>
username2: ${user.setUserName("kkk")}<br/>
username1: ${user.getUserName()}<br/>
</body>
顯示:
username1: 張三
username2:
username1: kkk
由於$user.setUserName("kkk ") 是void返回值方法,所以不會顯示任何東西.
有大括號的是正規方式引用(取值),也可以使用簡潔方式(去掉大括號),如:
$username
不過一些特殊場合必須加,如有一個vice變量
${vice}hello
如果不加就成了$vicehello,找不到變量了
取值的規則
$customer.address
查找順序是:
1、getaddress()
2、getAddress()
3、get("address")
4、isAddress()
大寫的屬性名Address引用,將是:
1、getAddress()
2、getaddress()
3、get("Address")
4、isAddress()
默認顯示空白
如果取值失敗,默認會原樣顯示,如$user,如果user沒定義,就會直接顯示出來,可以加感嘆號讓他顯示空白,如$!user或者$!{user}
set用法
set設置變量
set可以設置各種變量類型,如:
#set( $monkey = $bill ) ## 設置變量
#set( $monkey.Friend = "monica" ) ## 設置字符串
#set( $monkey.Blame = $whitehouse.Leak ) ## 設置變量的屬性
#set( $monkey.Plan = $spindoctor.weave($web) ) ## 設置方法返回值
#set( $monkey.Number = 123 ) ##設置數字
#set( $monkey.Say = ["Not", $my, "fault"] ) ## 設置ArrayList
#set( $monkey.Map = {"banana" : "good", "roast beef" : "bad"}) ## 設置Map
其中ArrayList用中括號,Map用大括號,跟json格式一樣
ArrayList訪問元素:
$monkey.Say.get(0)
Map訪問元素
$monkey.Map.get("bannana")或者$monkey.Map.banana
注:set賦值時,如果賦值失敗或者賦的是null值,都不會生效,如:
#set( $result = "kkk" )
$result
<br/>
#set( $result = $user.userName )
$result
此時如果user對象不存在或者user.userName是null,都不會賦值,都輸出
kkk
kkk
注:set賦值變量時,如果右邊是單引號,則不會取變量值,原樣輸出,如果是雙引號,則會取出變量值,如:
1、單引號,原樣輸出:
#set($a = "kkk" )
#set($b = "ggg")
#set($c = '$a + $b')
$c
輸出:
$a + $b
也可以通過配置來讓他轉義:
velocity.properties such that stringliterals.interpolate=false.
2、雙引號,變量轉義后輸出
#set($a = "kkk" )
#set($b = "ggg")
#set($c = "$a + $b")
$c
輸出
kkk + ggg
3、沒有符號,做運算
#set($a = "kkk" )
#set($b = "ggg")
#set($c = $a + $b)
$c
輸出:
kkkggg
set計算
類似於jstl,vtl也能做計算,如:
#set($foo = 5)
#set($bar = 6)
#set( $value = $foo + 1 )
$value<br/>
#set( $value = $bar - 1 )
$value<br/>
#set( $value = $foo * $bar )
$value<br/>
#set( $value = $foo / $bar )
$value<br/>
輸出:
如果是字符串,則直接拼接,如:
#set($foo = "5")
#set($bar = "6")
#set( $value = $foo + 1 )
$value<br/>
#set( $value = $bar - 1 )
$value<br/>
#set( $value = $foo * $bar )
$value<br/>
#set( $value = $foo / $bar )
$value<br/>
輸出:
這里字符串只有+運算,-*/都沒有,所以失敗了,value的值沒變(set賦值失敗,原值不變),只有第一次"5"+"1"成功了,所以輸出4個51
注:單引號跟雙引號一樣,都是字符串拼接
原樣輸出用#liternal() ….#end,不解析vtl
如:
#set($a=5)
#literal()
${a}
#end
輸出${a}而不是5
if語句
如后台設置了:
ctx.put("a", 1);
vm頁面:
#if($a == '1')
true enough
#elseif($a == '2')
a is 2
#else
no way!
#end
輸出:true enough
另:
$a == '1'
$a == 1
$a == "1"
三個都一樣。
如果if、else等關鍵字前或后緊跟了其他字符,則可以用大括號隔開,如:
#if($a == "1")
true enough#{else}no way!
#end
注意:判斷條件中如果只有一個變量,則只有當該變量找不到或者為null或者為false時,才不成立,其他時候都成立,如:
例1、
#set($a="abc")
#if($a)
yes
#else
no
#end
輸出:yes
例2、
#set($a="abc")
#if($a.b)
yes
#else
no
#end
輸出:no
3、
#set($a=false)
#if($a)
yes
#else
no
#end
輸出:no
注意:vtl中的所有數據類型都是對象,沒有java中的int等類型,==比較時,都是調用toString方法,int等類型會自動轉成Integer的封裝。
支持與或非等語法,如:
#if($a && $b)
#if(!($a || $b))
等
for循環語句
遍歷list(array)
后台代碼:
List<User> users = new ArrayList<User>();
User user1 = new User("zhangsan", 29);
User user2 = new User("lisi", 99);
users.add(user1);
users.add(user2);
ctx.put("users", users);
return getTemplate("test.vm");
vm代碼:
#foreach($user in $users)
index:$velocityCount
username:$user.userName
age:$user.age
<br/>
#end
輸出:
index:1 username:zhangsan age:29
index:2 username:lisi age:99
其中$velocityCount可以取得當前序號(計數器).
遍歷map
后台代碼:
Map<String, User> usersMap = new HashMap<String, User>();
User user1 = new User("wangwu", 30);
User user2 = new User("zhaoliu", 100);
usersMap.put("user1", user1);
usersMap.put("user2", user2);
ctx.put("usersMap", usersMap);
return getTemplate("test.vm");
vm代碼:
#foreach($user in $usersMap)
index:$velocityCount
username:$user.userName
age:$user.age
<br/>
#end
或者
#foreach($userKey in $usersMap.keySet())
index:$velocityCount
username:$usersMap.get($userKey).userName
age:$usersMap.get($userKey).age
<br/>
#end
輸出:
index:1 username:zhaoliu age:100
index:2 username:wangwu age:30
$velocityCount的名字、初始值也可以進行配置,如:
directive.foreach.counter.name = myVelocityCount
directive.foreach.counter.initial.value = 100
名字就改成了myVelocityCount,初始值為100
include和parse包含
類似於jsp的include包含,如:
#include("a.vm")
#include("b.txt")
#parse("c.vm")
#include( "one.gif","two.txt","three.htm" )
#include( "greetings.txt", $seasonalstock )
include包含的文件不會被解析,原樣顯示。
parse包含的文件會解析。
是否解析跟包含文件擴展名無關,只跟include還是parse命令有關
include可以一次包含多個,也可用變量名指定文件名
parse只能包含一個。
被#parse 的模板中還可以再包含#parse聲明,默認的深度為10,這是由配置參數directive.parse.max.depth決定的
stop
stop之后的內容停止輸出(不僅是不解析,而且是所有的文件內容都不輸出),以便用於調試,如:
#set($a = 6)
$a
#stop
abc
$a
輸出:6
宏調用macro
無參宏
類似於freemarker,可以定義宏,解析之前自動替換內容,再解析,如:
#macro( d )
welcome!
#end
#d()
輸出:
welcome!
這里用macro定義了名稱為d的宏,然后用#d()調用宏。
注意:宏定義改了之后,需要重啟服務才會生效(調試時需注意)
帶參數宏
如例1:
#macro(d $a $b)
hello,$a,$b
#end
#d("zhangsan", "lisi")
輸出:
hello,zhangsan,lisi
其中,$a和$b是參數
例2:
#macro(d $color $userList)
color is $color </br>
#foreach($user in $userList)
$user <br/>
#end
#end
#d("black", ["zhangsan", "lisi", "wangwu"])
輸出:
color is black
zhangsan
lisi
wangwu
這里傳了一個String參數$color和一個Arraylist參數$userList
轉義
引用的轉義
有時需要輸出$、#這些
$2.5輸出:$2.5 不會有問題,因為變量不能以數字開頭
斜杠表示轉義:
#set( $email = "foo" )
輸出:
foo
\foo
\\$email相當於\\ + $email,轉義的斜杠+變量值,所以是\foo
\\\$email相當於\\ + \$email,轉義的斜杠+轉義的變量,所以是\$email
如果$email沒有定義,則原樣輸出:
命令的轉義
與引用轉義類似,在#號前加斜杠即可,
如
例1:
\#include( "a.txt" )
此時不會引入a.txt而是在頁面上直接輸出#include( "a.txt" )
例2:
\\#include ( "a.txt" )
此時輸出\加a.txt的內容。
例3:
\#if( $a )
hello
\#end
輸出:
例4:
#set($a = true)
\\#if( $a )
hello
\\#end
輸出:
因為\\被轉義成了\
例5:
#set($a = true)
\#if( $a )
hello
#end
編譯報錯,因為只有#end,而#if被轉義了。
范圍操作,如:[3..5]等
范圍操作邊界只能是整數,每次遞增(遞減)1.
實質是生成了一個數組,只能用於#foreach或者#set命令標簽。
一般用於網頁設計者設計table等表格時,沒有足夠的填充數據時使用。
例1:
#foreach($a in [3..-2])
$a <br/>
#end
輸出:
3
2
1
0
-1
-2
例2:
#foreach($a in [3..3])
$a <br/>
#end
輸出:
3
例3:
#set($arr = [3..5])
#foreach($a in $arr)
$a <br/>
#end
輸出:
3
4
5
這里把范圍[3..5]賦值給了$arr(實質是生成了一個數組[3,4,5]),再循環遍歷