官網:http://velocity.apache.orghtml
Velocity是一個基於Java的模板引擎。它容許任何人使用簡單而強大的模板語言來引用Java代碼中定義的對象。java
當Velocity用於Web開發時,Web設計人員能夠與Java程序員並行工做,以根據模型 - 視圖 - 控制器(MVC)模型開發Web站點,這意味着網頁設計人員能夠專一於建立一個看起來很好的站點,程序員能夠專一於編寫一流的代碼。Velocity將Java代碼與網頁分開,使網站在其生命週期內更加可維護,併爲Java Server Pages(JSP)或PHP提供了可行的替代方案。程序員
Velocity的功能遠遠超出了網絡的範圍; 例如,它能夠用於從模板生成SQL,PostScript和XML。它能夠用做生成源代碼和報告的獨立實用程序,也能夠用做其餘系統的集成組件。例如,Velocity爲各類Web框架提供模板服務,使他們可以根據真正的MVC模型,使視圖引擎促進Web應用程序的開發。web
Velocity Engine——這是實現全部工做的實際模板引擎。(目前的版本是1.7)spring
Velocity Tools——項目包含使用Velocity引擎構建Web和非Web應用程序的工具和其餘有用的基礎設施。在此找到例如Struts集成的代碼或獨立的VelocityViewServlet。(目前的版本是2.0)數據庫
個人項目是用了Spring Boot的,開始想在Spring.io中直接添加Velocity的依賴,可是找不到依賴包,只能後面導入了。apache
個人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";就能夠了。
官方文檔:https://velocity.apache.org/engine/devel/user-guide.html
這個是Velocity的官方用戶指南,裏面寫了不少Veloctiy的語法和使用規範,下面就來試試看吧~
單行註釋以##開始;
多行註釋是 #* *#;
VTL註釋塊, #** *# ,主要是用來存儲類信息和做者版本信息。
變量的簡寫符號由前導「$」字符,後跟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"; } |
|
屬性具備獨特的格式,$和.組成:
例子,$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}
以$開頭,用.和()來表示引用方法,方法中間還能夠用 」」來填充參數。從Velocity 2.0開始,方法調用如今提供了全部Java基本內置類型之間的隱式轉換:數字,布爾和字符串。
上面的User中的get和set方法,實踐一下:
method:${user.getName()} method2:${user.setName("50")} method3:${user.getName()}
屬性一般引用父對象的方法,肯定哪一個方法對應所請求的屬性,Velocity根據下列命名約定嘗試不一樣的替代方法:
1. getaddress()
2. getAddress()
3. get("address")
4. isAddress()
將每一個引用(不管是變量,屬性仍是方法)生成的最終值在呈現爲最終輸出時都將轉換爲String對象。若是有一個表明$ foo的對象(例如Integer對象),那麼Velocity將調用它的.toString()方法來將對象解析成一個String。
使用表單的符號$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
示例: ${vice}
通常用簡寫的符號 $vice ,跟上面的意思是同樣的。可是因爲可能存在歧義,好比Jack is a $vicemaniac ,這個時候就須要用正式的參考符號來消除歧義。
當引用與模板中的文本直接相鄰時,正式符號一般頗有用。
這是 ! 的區別:
例如:
<input type="text" name="email" value="$email"/> <input type="text" name="email" value="$!email"/> <input type="text" name="email" value="$!{email}"/>
只有第一個框中有 $email ,後面兩個是沒有的。後面兩個框:當初始加載表單而且$ email仍然沒有值時,將輸出一個空字符串,而不是「$ email」。
Velocity 1.6引入了經過將速度配置屬性「runtime.references.strict」設置爲true來激活的嚴格參考模式的概念。這種設置的通常目的是使Velocity在未定義或不明確的狀況下更嚴格地執行,相似於編程語言,這可能更適合於Velocity的某些用途。在這種未定義或不明確的狀況下,Velocity會拋出異常。
使用此設置,引用須要被明確地放置到上下文中或者用#set指令定義,不然Velocity將拋出異常。在值爲null的上下文中的引用不會產生異常。另外,若是嘗試調用引用中沒有定義指定方法或屬性的對象的方法或屬性,那麼Velocity將拋出異常。若是嘗試在null值上調用方法或屬性,這也是正確的。
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}
指令以#開頭。
引用容許模板設計者爲網站生成動態內容,而指令 - 易於使用的腳本元素,可用於創造性地操縱Java代碼的輸出 - 容許網頁設計師真正負責網站的外觀和內容現場。
#set指令沒有#end語句,這個要特別注意。
#set($user.age=18) age:${user.getAge()}
當使用#set指令時,將會解析和呈現包含在雙引號字符中的字符串文字。可是,當字符串文字包含在單引號字符中時,將不會被解析。另外,Velocity提供 #[[don't parse me!]]# ,使[[]]中間的內容不被解析。
舉例:
#set( $directoryRoot = "www" )
#set( $templateName = "index.vm" )
#set( $template = "$directoryRoot/$templateName" )
$template
輸出爲:www/index.vm
#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引擎會在發現第一個爲真的表達式時中止。
Velocity的運算符有== ,&&,|| ,! ,跟Java差很少,可是略有不一樣的是,Java的==只能判斷對象是否相等,而Velocity是能夠直接比較數字、字符串、對象是否相等的,當對象不一樣時,會調用toString()方法來比較。
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
#include腳本元素容許模板設計者導入本地文件,而後將其插入到其中的位置的#include指令定義。該文件的內容不會經過模板引擎呈現。
示例:在templates下新建一個hello.vm
Title <h>$!titleLily<h>
而後在news.vm中include進去:
#set($title = "FastNews") Include: #include("hello.vm")<br>
運行的結果顯示,這裏的set並不會填充到hello.vm中。
#parse腳本元素容許模板設計者導入包含VTL的本地文件。Velocity將解析VTL並渲染指定的模板。像#include指令同樣,# parse可使用變量而不是模板。#parse引用的任何模板必須包含在TEMPLATE_ROOT下。與#include指令不一樣,# parse只會使用一個參數。
#parse("hello.vm")
運行結果顯示:這裏就能夠將title填充。
#break指令中止當前執行範圍的任何進一步渲染。「執行範圍」本質上是內容的任何指令(即#foreach,#parse,#evaluate,#define,#macro或#@ somebodymacro)或任何「根」範圍(即template.merge(...) Velocity.evaluate(...)或velocityEngine.evaluate(...))。與#stop不一樣,#break只會中止最內層,即時範圍,而不是所有。
中止模板的任何進一步的渲染和執行。
#evaluate指令可用於動態評估VTL。這容許模板評估在渲染時建立的字符串。這樣的字符串可能用於國際化模板或從數據庫中包含模板的部分。
示例:
#set($source1 = "abc") #set($select = "1") #set($dynamicsource = "$source$select") ## $dynamicsource is now the string '$source1' #evaluate($dynamicsource)
顯示的是abc而不是abc1.