Velocity入門

Velocity

1、什麼是Velocity?

官網:http://velocity.apache.org

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"?>
<project
xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>
4.0.0</modelVersion>

   <groupId>
com.LilyDianer</groupId>
   <artifactId>
FastNews</artifactId>
   <version>
0.0.1-SNAPSHOT</version>
   <packaging>
jar</packaging>

   <name>
FastNews</name>
   <description>
Demo project for Spring Boot</description>

      <parent>
         <groupId>
org.springframework.boot</groupId>
         <artifactId>
spring-boot-starter-parent</artifactId>
         <version>
1.3.5.RELEASE</version>
         <relativePath/>
<!-- lookup parent from repository -->
     
</parent>

      <properties>
         <project.build.sourceEncoding>
UTF-8</project.build.sourceEncoding>
         <java.version>
1.8</java.version>
      </properties>

      <dependencies>
         <dependency>
            <groupId>
org.springframework.boot</groupId>
            <artifactId>
spring-boot-starter-aop</artifactId>
         </dependency>
         <dependency>
            <groupId>
org.springframework.boot</groupId>
            <artifactId>
spring-boot-starter-velocity</artifactId>
         </dependency>
         <dependency>
            <groupId>
org.springframework.boot</groupId>
            <artifactId>
spring-boot-starter-web</artifactId>
         </dependency>

         <dependency>
            <groupId>
org.springframework.boot</groupId>
            <artifactId>
spring-boot-starter-test</artifactId>
            <scope>
test</scope>
         </dependency>
      </dependencies>

      <build>
         <plugins>
            <plugin>
               <groupId>
org.springframework.boot</groupId>
               <artifactId>
spring-boot-maven-plugin</artifactId>
            </plugin>
         </plugins>
      </build>
   </project>

 

然後在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.

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章