Velocity
1、什麼是Velocity?
Velocity是一個基於Java的模板引擎。它允許任何人使用簡單而強大的模板語言來引用Java代碼中定義的對象。
當Velocity用於Web開發時,Web設計人員可以與Java程序員並行工作,以根據模型 - 視圖 - 控制器(MVC)模型開發Web站點,這意味着網頁設計人員可以專注於創建一個看起來很好的站點,程序員可以專注於編寫一流的代碼。Velocity將Java代碼與網頁分開,使網站在其生命週期內更加可維護,併爲Java Server Pages(JSP)或PHP提供了可行的替代方案。
Velocity的功能遠遠超出了網絡的範圍; 例如,它可以用於從模板生成SQL,PostScript和XML。它可以用作生成源代碼和報告的獨立實用程序,也可以用作其他系統的集成組件。例如,Velocity爲各種Web框架提供模板服務,使他們能夠根據真正的MVC模型,使視圖引擎促進Web應用程序的開發。
2、Velocity提供的project
Velocity Engine——這是實現所有工作的實際模板引擎。(目前的版本是1.7)
Velocity Tools——項目包含使用Velocity引擎構建Web和非Web應用程序的工具和其他有用的基礎設施。在此找到例如Struts集成的代碼或獨立的VelocityViewServlet。(目前的版本是2.0)
3、入門示例
我的項目是用了Spring Boot的,開始想在Spring.io中直接添加Velocity的依賴,但是找不到依賴包,只能後面導入了。
我的porm.xml如下:
<?xml version="1.0"encoding="UTF-8"?> <parent> |
然後在resource/templates下新建一個news.vm
<html> <body> <pre> Hello Lily Velocity </pre> </body> </html> |
然後在src/main/java下新建一個controller包,在該包中新建一個IndexController類,添加Controller註解,寫一個news函數:
@Controller public class IndexController { @RequestMapping(value= {"/vm"} ) public String news(){ return "news"; } } |
然後運行Application,在127.0.0.1:8080中查看:
第一次報錯:
Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback. Thu Jul 27 13:10:00 CST 2017 There was an unexpected error (type=Not Found, status=404). No message available |
看了控制檯提示的錯誤:
2017-07-27 13:10:56.038 ERROR 8872 --- [nio-8080-exec-1] org.apache.velocity : ResourceManager : unable to find resource 'news.vm.vm' in any resource loader. 2017-07-27 13:10:56.065 ERROR 8872 --- [nio-8080-exec-1] org.apache.velocity : ResourceManager : unable to find resource 'error.vm' in any resource loader. |
因爲我開始寫的是:
return "news.vm";
但是其實Velocity是會默認給返回值後面再加一個.vm,所以就報錯了。
改成return "news";就可以了。
4、User-guide
官方文檔:https://velocity.apache.org/engine/devel/user-guide.html
這個是Velocity的官方用戶指南,裏面寫了很多Veloctiy的語法和使用規範,下面就來試試看吧~
1、註釋Comment
單行註釋以##開始;
多行註釋是 #* *#;
VTL註釋塊, #** *# ,主要是用來存儲類信息和作者版本信息。
2、References 引用
2.1 Variables變量
變量的簡寫符號由前導“$”字符,後跟VTL 標識符組成。VTL標識符必須以字母、數字和下劃線組成,其他字符無效。
當VTL引用變量(如$ foo)時,變量可以從模板中的set指令或Java代碼中獲取其值。例如,如果Java變量$ foo在請求模板時具有值欄,則bar將替換網頁上$ foo的所有實例。
舉例:項目要顯示用戶名。
首先需要importorg.springframework.ui.Model;
news.vm文件:
<html> <body> <pre> Hello Lily Velocity ##這裏是註解 #* * 這裏還是註解 * *# username: $!{username} </pre> </body> </html>
|
IndexController.java:
@RequestMapping(value= {"/vm"} ) public String news(Model model){ model.addAttribute("username","Lily"); return "news"; } |
2.2 Properties屬性
屬性具有獨特的格式,$和.組成:
例子,$customer.Address。它可以有兩個含義。這可以意味着,查看標識爲客戶的哈希表,並返回與地址相關聯的值。但是$ customer.Address也可以指一個方法(參考方法的引用將在下一節討論);$ customer.Address可以是一個寫入$ customer.getAddress()的縮寫方式。當您的頁面被請求時,Velocity將確定這兩種可能性中的哪一種是有意義的,然後返回適當的值。
項目的實例:首先需要在model包中寫一個User類,屬性有name和age,並且需要生成對應的setter和getter方法,和構造方法:
然後在Controller中寫:
model.addAttribute("user",new User("Dianer",23));
然後在news.vm中寫:
User:${user.name} User:${user.age}
2.3 Methods方法
以$開頭,用.和()來表示引用方法,方法中間還可以用 ””來填充參數。從Velocity 2.0開始,方法調用現在提供了所有Java基本內置類型之間的隱式轉換:數字,布爾和字符串。
上面的User中的get和set方法,實踐一下:
method:${user.getName()} method2:${user.setName("50")} method3:${user.getName()}
2.4 Property Lookup Rules 屬性查找規則
屬性通常引用父對象的方法,確定哪個方法對應所請求的屬性,Velocity根據下列命名約定嘗試不同的替代方法:
1. getaddress()
2. getAddress()
3. get("address")
4. isAddress()
2.5 Rendering 渲染
將每個引用(無論是變量,屬性還是方法)生成的最終值在呈現爲最終輸出時都將轉換爲String對象。如果有一個代表$ foo的對象(例如Integer對象),那麼Velocity將調用它的.toString()方法來將對象解析成一個String。
2.6 Index Notation 索引符號
使用表單的符號$foo[0]可以用於訪問對象的給定索引。此形式與在給定對象上調用get(Object)方法同義。
$foo[0] ## $foo takes in an Integer look up
$foo[$i] ## Using another reference as the index
$foo["bar"] ## Passing a string where $foo may be a Map
3、Formal Reference Notation正式參考符號
示例: ${vice}
一般用簡寫的符號 $vice ,跟上面的意思是一樣的。但是由於可能存在歧義,比如Jack is a $vicemaniac ,這個時候就需要用正式的參考符號來消除歧義。
當引用與模板中的文本直接相鄰時,正式符號通常很有用。
4、Quiet Reference Notation安靜參考符號
這是 ! 的區別:
例如:
<input type="text" name="email" value="$email"/> <input type="text" name="email" value="$!email"/> <input type="text" name="email" value="$!{email}"/>
只有第一個框中有 $email ,後面兩個是沒有的。後面兩個框:當初始加載表單並且$ email仍然沒有值時,將輸出一個空字符串,而不是“$ email”。
5、Strict Reference Mode嚴格參考符號
Velocity 1.6引入了通過將速度配置屬性“runtime.references.strict”設置爲true來激活的嚴格參考模式的概念。這種設置的一般目的是使Velocity在未定義或不明確的情況下更嚴格地執行,類似於編程語言,這可能更適合於Velocity的某些用途。在這種未定義或不明確的情況下,Velocity會拋出異常。
使用此設置,引用需要被明確地放置到上下文中或者用#set指令定義,否則Velocity將拋出異常。在值爲null的上下文中的引用不會產生異常。另外,如果嘗試調用引用中沒有定義指定方法或屬性的對象的方法或屬性,那麼Velocity將拋出異常。如果嘗試在null值上調用方法或屬性,這也是正確的。
6、Case Substitution 案例替換
Velocity利用Java的內省和bean特性,將Context中的對象的引用名稱以及objects方法解析。可以在模板中幾乎任何地方嵌入和評估引用。
以SunMicrosystems定義的Bean規範爲基礎的Velocity是區分大小寫的; 然而,其開發人員儘可能地努力捕捉和糾正用戶錯誤。當方法getFoo()在模板中引用時$bar.foo,Velocity將首先嚐試$getfoo。如果這樣做失敗,那麼會嘗試$getFoo。同樣,當模板引用時$bar.Foo,Velocity會首先嚐試$ getFoo(),然後嘗試getfoo()。
注意:模板中對實例變量的引用未解決。只有引用JavaBean getter / setter方法的屬性等同於解析(即$foo.Name解析爲Foo類的getName()實例方法,而不是Foo的公共Name實例變量)。
相同的示例有:
$foo.getBar()
## is the same as
$foo.Bar
$data.setUser("jon")
## is the same as
#set( $data.User = "jon" )
$data.getRequest().getServerName()
## is the same as
$data.Request.ServerName
## is the same as
${data.Request.ServerName}
7、Directives指令
指令以#開頭。
引用允許模板設計者爲網站生成動態內容,而指令 - 易於使用的腳本元素,可用於創造性地操縱Java代碼的輸出 - 允許網頁設計師真正負責網站的外觀和內容現場。
7.1、Set
#set指令沒有#end語句,這個要特別注意。
#set($user.age=18) age:${user.getAge()}
7.1.1、Literals文本
當使用#set指令時,將會解析和呈現包含在雙引號字符中的字符串文字。但是,當字符串文字包含在單引號字符中時,將不會被解析。另外,Velocity提供 #[[don't parse me!]]# ,使[[]]中間的內容不被解析。
舉例:
#set( $directoryRoot = "www" )
#set( $templateName = "index.vm" )
#set( $template = "$directoryRoot/$templateName" )
$template
輸出爲:www/index.vm
7.2、Conditionals條件語句
7.2.1、If / ElseIf / Else
#if( $user ) <strong>Velocity!</strong> #end
#set($foo=10) #if( $foo < 10 ) **Go North** #elseif( $foo == 10 ) **Go East** #elseif( $bar == 6 ) **Go South** #else **Go West**
Velocity會對if後的($foo)進行評估,確定是否爲真:
$ foo是一個具有真實值的布爾值(true/ false)
$ foo的是一個字符串或一個集合,其不爲空和不爲空
$ foo是等於零的數字
$ foo是一個不爲空的對象(字符串,數字或集合除外)
使用if elseif 的時候,Velocity引擎會在發現第一個爲真的表達式時停止。
7.2.2、Relational and LogicalOperators 關係和邏輯運算符
Velocity的運算符有== ,&&,|| ,! ,跟Java差不多,但是略有不同的是,Java的==只能判斷對象是否相等,而Velocity是可以直接比較數字、字符串、對象是否相等的,當對象不同時,會調用toString()方法來比較。
7.3、Loops循環
7.3.1、Foreach Loop
Velocity使用foreach循環。對象可以是Vector,HashMap或者是Array。
(1)當對象是Array時:
Controller:
List<String> colors = Arrays.asList(new String[]{"RED", "GREEN", "BLUE"}); model.addAttribute("colors", colors);
news.vm
#foreach ($color in $colors) Color $!{foreach.index}/$!{foreach.count}: $!{color} #end
(2)當對象是map時:
Controller:
Map<String, String> map = new HashMap<String, String>(); for (int i = 0; i < 4; ++i) { map.put(String.valueOf(i), String.valueOf(i * i)); } model.addAttribute("map", map);
news.vm:
#foreach($key in $map.keySet()) Number $!{foreach.index}/$!{foreach.count}: $!{key} $map.get($key) #end
7.4、Include 包含
#include腳本元素允許模板設計者導入本地文件,然後將其插入到其中的位置的#include指令定義。該文件的內容不會通過模板引擎呈現。
示例:在templates下新建一個hello.vm
Title <h>$!titleLily<h>
然後在news.vm中include進去:
#set($title = "FastNews") Include: #include("hello.vm")<br>
運行的結果顯示,這裏的set並不會填充到hello.vm中。
7.5、Parse解析
#parse腳本元素允許模板設計者導入包含VTL的本地文件。Velocity將解析VTL並渲染指定的模板。像#include指令一樣,# parse可以使用變量而不是模板。#parse引用的任何模板必須包含在TEMPLATE_ROOT下。與#include指令不同,# parse只會使用一個參數。
#parse("hello.vm")
運行結果顯示:這裏就可以將title填充。
7.6、Break
#break指令停止當前執行範圍的任何進一步渲染。“執行範圍”本質上是內容的任何指令(即#foreach,#parse,#evaluate,#define,#macro或#@ somebodymacro)或任何“根”範圍(即template.merge(...) Velocity.evaluate(...)或velocityEngine.evaluate(...))。與#stop不同,#break只會停止最內層,即時範圍,而不是全部。
7.7、Stop
停止模板的任何進一步的渲染和執行。
7.8、Evaluate 評估
#evaluate指令可用於動態評估VTL。這允許模板評估在渲染時創建的字符串。這樣的字符串可能用於國際化模板或從數據庫中包含模板的部分。
示例:
#set($source1 = "abc") #set($select = "1") #set($dynamicsource = "$source$select") ## $dynamicsource is now the string '$source1' #evaluate($dynamicsource)
顯示的是abc而不是abc1.