程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 使用Velocity實現客戶端和服務器端模板

使用Velocity實現客戶端和服務器端模板

編輯:關於JAVA

在 HTML 或者 XML 這樣的標准表示或交換格式中,文本性數據的操作和轉換是一種頻繁而且通常非常單調的活動,每個開發人員都會遇到。模板引擎可以改善這個過程,它在模板中保留輸出中的靜態部分,而動態生成和安排變化的部分。Velocity 是一種高度實用的、開放源代碼的模板引擎,可以方便地集成到其他客戶端或服務器端應用程序中。

對於服務器端應用程序,如果與兼容 Servlet 2.3+ 的 Web 層容器集成,Velocity 為 JSP 技術提供了一種可行的替代方案,可以強制實施表示邏輯與應用程序業務邏輯的清晰劃分。事實上,Velocity 支持的模板語言非常簡單,形成的模板也十分清晰,Web 站點設計人員和樣式開發人員可以學習和維護這些模板。

本文中將考察 Velocity 的簡單模板語言、創建一些模板並將其用於獨立的客戶應用程序。然後我們將把這個模板引擎集成到 Struts MVC 框架中作為視圖組件。

基本模板引擎操作

基本模板引擎操作非常簡單。首先看一看清單 1 中的模板:

清單 1. 基本的 Velocity 模板

<html>
<head>
<title>A Template Based Page</title>
</head>
<body>
<p>This is a page generated by $generatedBy.</p>
<p>The customer's name is $customerName.</p>
</body>
</html>

這個模板是一個完整的 HTML 文件。您可以使用文本編輯器或者喜歡的圖形化可視網頁編輯器創建該文件。創建的簡易性是基於模板的系統的主要好處和要求。

當模板引擎運行時,清單 1 中彩色顯示的部分將被實際的數據替換。獲取數據並與模板結合的過程稱為 合並。看一看清單 2 中的腳本所表示的數據:

清單 2. 為模板合並設置數據值

#set ($generatedBy = "Velocity")
#set ($customerName = "John Doe")

現在,如果清單 1 中的模板與清單 2 中的數據合並,將得到清單 3 所示的結果:

清單 3. 合並到模板中的數據

<html>
<head>
<title>A Template Based Page</title>
</head>
<body>
<p>This is a page generated by Velocity.</p>
<p>The customer's name is John Doe.</p>
</body>
</html>

您可能發現,這種特性和字處理程序中的郵件合並功能類似。在字處理程序中,信函結構與來自郵件列表的名稱和地址合並。和郵件合並一樣,這種應用程序最適用於要合並的數據源非常大而且有變化的情況。

從這個單純的意義上講,Velocity 是一個模板引擎。Velocity 的輸出格式僅受文本模板中所能放置的內容的限制。包括現在最流行的格式(HTML、XML、SQL,等等)。

使用 Velocity 模板語言創建模板

Velocity 模板是文本文件(HTML、XML 等等),其中包括:

照原樣合並的靜態部分

將被要合並的數據替代的占位符

腳本語言中的指示符和指令

Velocity 模板使用的腳本語言稱為 Velocity 模板語言(VTL)。和其他腳本語言相比,VTL 語法相對而言不是很豐富。任何具有編程背景的人都可以非常快地學會 VTL。

占位符與引用

VTL 中的引用是一個命名元素,如 $customerName 。引用可以在 Velocity 模板中作為占位符。在模板合並過程中,這些占位符將被替換成相應的文本值,從而形成最終的輸出。比如,在 清單 1 中,我們可以看到使用了兩個 VTL 引用( $generatedBy 和 $customerName )已生成最終輸出結果。

變量在 VTL 中是一種引用類型。您可以使用 #set() 指示符為變量賦值。清單 4 給出了一些例子:

清單 4. 變量類型的 VTL 引用

#set( $this = "Velocity")
#set( $numericBase = 999 )
#set( $booleanCondition = true )
This page is generated using $this.
There are ($numericBase + 1) pages in total.

變量名必須從一個字母開始,因此 Velocity 很容易把變量名與模板中的貨幣符號分開(比如, $100 不可能是一個變量名)。合並操作中所有的變量都被轉化成字符串,可能造成一些有趣的現象。看一看清單 4 中用紅色顯示的文本。合並後的輸出如清單 5 所示:

清單 5. 合並後的模板中帶有數字值的變量

This page is generated using Velocity.
There are (999 + 1) pages in total.

因為 $numericBase 在合並操作中被轉化成了字符串,因此不會執行算術操作。因為 VTL 專門用於模板操作而非通用的計算語言,所以只需要支持整數算術運算(盡管可以使用插件工具進行擴展)。下面的腳本說明了如何利用這種數學運算能力:

#set( $newSum = $numericBase + 1)
There are $newSum pages in total.

該模板合並後相應的輸出為:

There are 1000 pages in total.

到目前我們處理的還只有標量。要創建包含多個元素的 ArrayList 變量,可以使用如下的語法:

#set( $treeList = ["pine", "oak", "maple", "redwood"])

您可以使用 $treeList.get(1) 列表中的第二個元素。

賦值以後, $treeList 就是一個基於 ArrayList 的變量(就像是標准 JDK 集合類中那樣)。您可以直接使用符號 $treeList.get(n) 訪問它的每個元素,其中的 n 是以 0 為基的 ArrayList 索引。比如,像 清單 6 種紅色顯示的一行所表明的那樣, $treeList.get(1) 用於選擇 ArrayList 中第二項,即 oak。這種調用 ArrayList 類方法的語法也可用於調用其他變量對象的方法。

屬性和方法參考

除了在模板中設置變量之外,VTL 引用也可以是對象屬性或方法。這些對象是模板可以使用的 Java 類。

對象屬性通過和 Javabean 類似的符號訪問。比如,可以通過 VTL 引用 $customer.LastName 訪問 $customer 對象的 LastName 屬性。在幕後,Velocity 使用對象的訪問器方法獲得屬性值(即調用對象的 getLastName() 方法)。

您可以用和屬性訪問類似的符號調用對象的方法,可以帶參數列表也可以不帶。比如,可以通過 VTL 引用 $customer.getPhone("mobile") ,調用 $customer 對象的 getPhone() 方法獲得移動電話號碼。

關於占位符替換的一點說明:Velocity 把任何不能識別的引用作為普通文本打印,如清單 6 中下面突出顯示的兩行(藍色和紅色)所示:

清單 6. 占位符置換

The second item in the list is $treeList.get(1).
$notDeclared is an undeclared variable.
But $!notDeclared is invisible when not declared.

VTL 支持一種靜態引用符號,以避免呈現不存在的或者 空的 引用。如果使用安靜引用符號,比如 $!notDeclared ,那麼 Velocity 將什麼也不輸出,而不是輸出完整的引用名。注意變量名前面的“!”表示這是靜態引用符號。當合並清單 6 中的模板時,兩個引用都沒有分配任何值,但是藍色顯示的引用將原樣顯示,而綠色的一個則看不到:

The second item in the list is oak.
$notDeclared is an undeclared variable.
But is invisible when not declared.

選擇性呈現和循環

可以使用指示符 #if... #then... #else.... 有條件地呈現模板中特定的部分。清單 7 給出了一個例子:

清單 7. 使用 #if、#then 和 #else 有選擇地呈現

#if $customer.GoldMember
  Thank you Mr. $customer.LastName, for flying with us.
  Your loyal patronage is greatly appreciated.
  This flight earns you an additional 5000 miles.
#else
  Thank you for flying with us.
  Please consider joining our frequent flyer program.
#endif

在清單 7 的模板中,使用 $customer 對象的 boolean 屬性 GoldMember 確定在最終輸出中出現哪些信息。對於金牌顧客,最終輸出中將呈現藍色顯示的消息;對於其他顧客,則在最終輸出中呈現綠色顯示的消息。

模板中經常要使用循環格式化表格或者列表形式的信息。顯示的數據通常保存在一個 ArrayList 引用中。在 Velocity 中唯一用於處理重復循環的指示符是 #foreach 指示符。清單 8 中的模板通過 $treeList ArrayList 變量演示了 #foreach 指示符的用法。當然,也可以使用任何其他可用的集合類型的對象引用,或者返回一個集合的對象屬性/方法引用。

清單 8. 使用 #foreach 循環

<table>
<tr><td>Tree Name</td></tr>
#foreach $name in $treeList
<tr><td>
    $name is a big tree!
</td></tr>
#end
</table>

$treeList 中包含樹名的列表,清單 8 中的模板合並後的輸出如清單 9 所示:

清單 9. #foreach 循環中合並後的輸出

<table>
<tr><td>Tree Name</td></tr>
<tr><td>
    pine is a big tree!
</td></tr>
<tr><td>
    oak is a big tree!
</td></tr>
<tr><td>
    maple is a big tree!
</td></tr>
<tr><td>
    redwood is a big tree!
</td></tr>
</table>

如果從 HTML 浏覽器中查看,清單 9 當然就是一個包含樹名的表。

注意在 #foreach 循環體內有一個內置的計數器,可以在 #foreach 指示符循環體內通過 $velocityCounter 引用訪問它。默認情況下,這個計數器從 1 開始,每執行一次循環遞增一次。

Velocity 中的宏

Velocity 的一個主要特性是能夠很容易地定義宏,稱為 Velocimacros。宏使您能夠很容易地封裝和重用模板腳本。默認情況下,宏保存在 VM_global_library.vm 文件中。比如,考慮清單 10 中名為 #showTree() 的 Velocimacro:

清單 10. 定義 Velocimacro

#macro (showTree)
   #if ($treeList )
     #foreach ($e in $treeList )
       $e
     #end
   #end
#end

您可以調用 #showTree() Velocimacro 並使用它打印 $treeList ArrayList ―― 如果這個列表已經定義的話。調用的語法很簡單,即 #showTree() 。

參數化宏也是可能的。比如,我們可以修改 #showTree() 宏使其用於任何列表,如清單 11 所示:

清單 11. 帶參數的 Velocimacro

#macro (showList $val)
   #if ($val )
     #foreach ($e in $val )
       $e
     #end
   #end
#end

要使用清單 11 中的宏調用 $treeList ,我們可以使用 #showList($treeList) 。這兩種情況的輸出都一樣,如清單 12 所示:

清單 12. Velocimacro 的合並輸出

pine
    oak 
    maple
    redwood

其他有趣的 VTL 細節

單行注釋或者行尾注釋從 ## 開始,多行注釋則放在 #* 和 *# 之間。

在處理字符串數據時,可以使用雙引號或單引號分隔。但是使用雙引號允許在分隔的字符串 內部對 Velocity 引用、指示符甚至 Velocimacros 求值。

Velocity 上下文

您可以把 Velocity 中的上下文看作是導入 Java 對象,以便在 Velocity 模板內部訪問的一種方法。這種導入必須在 Java 編碼中明確地完成。和 JSP 代碼或者 JavaScript 不同,不存在“自然的”或“原生方式”使 Velocity 訪問任何 Java 對象。只有明確導入的 Java 對象才能在 Velocity 模板中使用。

通過創建 org.apache.velocity.context.Context 類的實例可以獲得 Velocity 上下文。然後可以使用上下文的 put( key, value) 方法,把將要導入供模板使用的對象附加到上下文中。key 是一個字符串名,將在模板中作為可用的引用出現。在產品環境中,圖形或者 Web 設計人員可能負責創建和維護模板,而 Java 開發人員提供可以在模板中訪問的對象集。在這種情況下,設計人員和開發人員應就對象集合及其可用的屬性達成一致並互相協作。在 Velocity 上下文中附加的屬性將作為主要的接口機制。

在模板中訪問上下文屬性

看一看一個獨立解析器中包含的示例代碼。可以在 \code\src 目錄下找到。比如,在 com.ibm.dvworks.velocity.VelocityParser 類中,我們已經創建並向 Velocity 上下文中添加了兩個屬性,如清單 13 所示:

清單 13. 在 VelocityParser 類中創建一個 Velocity 實例

public static void main(String[] args)  {
     VelocityParser velInstance = new VelocityParser(args[0]);
     velInstance.addToContext( "treeFarm",
     new String [] { "redwood", "maple", "oak", "pine" });
     velInstance.addToContext( "title", "A Tree Farm");
velInstance.addToContext( "date", new java.util.Date());
     velInstance.addToContext("fmtr",
     new org.apache.velocity.app.tools.VelocityFormatter(
          velInstance.getCurrentContext()));
     velInstance.processTemplate();
   }

屬性 treeFarm 是一個關於樹名的 ArrayList 。title 屬性是一個標量字符串。一旦附加到上下文中並在合並過程中傳遞,這些屬性在 Velocity 模板中立刻就變得沒有用了。清單 14 中的模板使用了這兩個屬性。您可以在 \code\app\treectx.vm 中找到這個例子。

清單 14. 使用 $treeFarm 上下文屬性引用

<table>
<tr><td>$title</td></tr>
#foreach $name in $treeFarm 
<tr><td>
    $name is a big tree!
</td></tr>
#end
</table>

合並後的輸出如清單 15 所示:

清單 15. 模板的合並輸出

<table>
<tr><td>A Tree Farm</td></tr>
<tr><td>
    redwood is a big tree!
</td></tr>
<tr><td>
    maple is a big tree!
</td></tr>
<tr><td>
    oak is a big tree!
</td></tr>
<tr><td>
    pine is a big tree!
</td></tr>
</table>

要注意,使用 $treeFarm 上下文屬性引用的方法和前面分析的 $treeList 變量引用一致。

初始化模板引擎

分析 VelocityParser 類中列出的 main() 方法(參見清單 13)。VelocityParser 構造函數創建解析器並加載模板,然後增加模板引擎要使用的屬性,最後調用 processTemplate() 合並數據和模板。我們將按照順序依次分析這些方法。

您可以在 org.apache.velocity.app.Velocity 類中使用靜態方法初始化 Velocity 並加載一個模板文件。要使用的方法分別為 init() 和 getTemplate() 。對 init() 方法的調用出現在 VelocityParser 類的構造函數中,如清單 16 所示:

清單 16. 在 VelocityParser 類的構造函數中初始化模板引擎

public VelocityParser(String templateFile) {
     try {
       Velocity.init("velocity.properties");
       mainTemplate = Velocity.getTemplate(templateFile);
      }
      catch( Exception ex ) {
         System.out.println("Error processing template file: " + templateFile );
      }
    }

在清單 16 中,對 init() 的調用創建了一個 Velocity 引擎實例。如果應用程序需要創建和管理多個 Velocity 模板引擎實例,則應使用 org.apache.velocity.app.VelocityEngine 類。

上下文鏈

只要調用 org.apache.velocity.VelocityContext 類的普通構造函數就可以創建直接可用的 Velocity 上下文。

Velocity 上下文可以 進行鏈接(包裝在另一個上下文內部)。如果需要在模板中控制特定對象引用的可見性和可用性,這樣做非常有用。

Velocity 將在對象引用的所有鏈接上下文中搜索屬性。如果遇到重復的名稱,則使用最外層的屬性,而內部的同名屬性永遠不會被訪問。

為了鏈接 Velocity 上下文,要鏈接的上下文應該作為參數傳遞給一個新上下文的構造函數。清單 17 中 VelocityParser 類的重載方法 addToContext() 說明了這一點:

清單 17. 使用 addToContext() 方法增加上下文屬性或者上下文鏈接

public void addToContext(String key, Object value) {
      if (mainContext == null)
        mainContext = new VelocityContext();
       mainContext.put(key, value);
    }
    public void addToContext(VelocityContext chainCtx) {
      mainContext = new VelocityContext(chainCtx);
    }

在 processTemplate() 方法中,調用模板的 merge() 方法結合上下文信息和模板生成輸出流,如清單 18 所示:

清單 18. 在 processTemplate() 方法中合並模板

public void processTemplate() {
      try {
       BufferedWriter writer = writer = new BufferedWriter(
         new OutputStreamWriter(System.out));
       if ( mainTemplate != null)
         mainTemplate.merge(mainContext, writer);
       writer.flush();
       writer.close();
     }
     catch( Exception ex )  {
       ex.printStackTrace();
     }
   }

Velocity 作為獨立的解析器

要編譯上述示例獨立解析器,請使用安裝目錄下 \code\app 中的 compile.bat 文件。要試驗該解析器,請使用 process.bat 批處理文件,其中包括:

set VEL_HOME=\jdk1.4\vel14rc1
java -classpath ..\classes;%VEL_HOME%\velocity-dep-1.4-rc1.jar
com.ibm.dvworks.velocity.VelocityParser %1 %2 %3

注意,必須同時在 compile.bat 和 process.bat 中把環境變量 VEL_HOME 設置成安裝 Velocity 的目錄。在 Velocity 發行包中包含兩類不同的 JAR 文件: velocity-dep---?.jar (其中的 --? 是版本號信息)和 velocity---?.jar 。velocity-dep---?.jar 文件包括所有的外部依賴(Jakarta common-collections、Avalon Logkit 和 ORO 正則表達式庫),可以直接使用。如果您的 classpath 中已經有一些這樣的庫,您可能希望使用 velocity---?.jar 文件來代替。如果這些 JAR 組成都不能滿足您的需要,可以很容易地按照需要的方式重新建立 Velocity。Velocity 發行包中包括一個 ant 腳本,可以為不同的應用場景建立 7 種不同的 JAR 配置。

為了便於上手,Velocity 預設了一些默認配置屬性,對於多數應用而言,這都是合理的和可以接受的。這就避免了開發人員從一開始就忙於復雜的配置選項,讓他們能馬上體驗到這種模板引擎。

服務器上的 Velocity 與 JSP 技術

在服務器端可以使用 Velocity 處理模板和生成的動態內容(HTML、XML等)。這和 JSP 技術的目標非常接近。但是,JSP 模型可以毫無阻礙地訪問底層的 Servlet API 和 Java 編程語言。事實上,為了避免訪問這些固有的特性,您在編碼中必須嚴格約束(只是使用 EL、標簽庫和類似的特性)。它基本上是一種在很大程度上開放的訪問模型。

拿 Velocity 與之比較。作為一種完全自包含的模板引擎和腳本解釋器,Velocity 擁有完全封閉的模型。任何針對系統和/或 Java 編程語言的訪問都必須明確地啟用。默認情況,Velocity 模板中不能訪問 Java 編程語言的任何方面。這種封閉的模型使 Velocity 能夠提供分離的模板表示層,與任何應用程序業務邏輯或者數據管理代碼清晰地劃分開。

現在讓我們把這種模板引擎與 Tomcat 5 的最新版本集成在一起,看一看 Velocity 在服務器端的應用。

與 Tomcat 5 一起部署 Velocity

Velocity 發行包帶有一個 org.apache.velocity.servletVelocityServlet 庫類,擴展它可以很快地創建一個模板處理 servlet。作為獨立的客戶機應用程序測試的任何模板都可以使用 VelocityServlet 部署在服務器上。把獨立的 Velocity 模板轉移到 Web 應用程序中相對比較簡單。只需要以下幾個步驟:

Velocity 中的工具

工具是在模板中可以通過 Velocity 上下文使用的實用 Java 對象。雖然可以手工把這些對象附加到上下文中,但 VelocityViewServlet 工具箱管理器可通過更加靈活和結構化的方式完成。在模板中一般是通過調用工具的方法來使用它們。VelocityViewServlet 與 VelocityStruts 都提供了非常有價值的經過測試的工具,在作為一種視圖技術部署 Velocity 時極其有用。

從 org.apache.velocity.servlet.VelocityServlet 類派生一個 Servlet 類。

重寫並實現其中的一個 handleRequest() 方法。

在 handleRequest() 的實現中,添加希望在模板中作為上下文屬性使用的數據或工具(請參閱 Velocity 中的工具)。

在 handleRequest() 的實現中,從文件或資源(如 JAR 文件)中取得模板並返回它。

在示例代碼包中, com.ibm.dvworks.velocity.VelTestServlet 就是按照上述步驟創建的一個 servlet。您可以查看 webapps\vservlet\WEB-INF\src 目錄下的代碼。如果改變了這些代碼,一定要使用 compile.bat 批處理文件重新編譯它。

部署描述符(web.xml 文件)定義了該 servlet 並把它映射到 /vServlet URL 模式中,如清單 19 所示:

清單 19. 自定義基於 Velocity 的 servlet 的 Tomcat 部署描述符

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
   "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
  <servlet>
   <servlet-name>vServlet</servlet-name>
   <servlet-class>com.ibm.dvworks.velocity.VelTestServlet</servlet-class>
  </servlet>
  <servlet-mapping>
   <servlet-name>vServlet</servlet-name>
   <url-pattern>/vServlet</url-pattern>
  </servlet-mapping>
</web-app>

加載並處理的模板放在 webapps\vServlet 目錄中。在這個例子中,模板文件稱為 variables.vm 。測試之前一定要保證 velocity-dep---?.jar 文件已經放在 webapps\vServlet\WEB-INF\lib 目錄下,然後啟動 Tomcat 5 並訪問 http://localhost:8080/vservlet/Servlet URL。

部署 VelocityViewServlet

要把模板功能擴展到 Web 應用程序中,應該使用 Velocity 工具集中的 VelocityViewServlet 。Velocity 工具是 Velocity 的一個子項目。該 Servlet 為 Velocity 用作一種視圖層技術提供了更復雜的支持,既可以與 JSP 技術聯合使用也可以代替後者。使用 VelocityViewServlet 可以減少許多冗余代碼,因為它提供了:

對請求對象和屬性、會話對象和屬性以及 servlet 上下文和屬性的直接模板訪問

正式的、可外部配置的“工具箱”,可以增加在模板中使用的自定義工具(這裡講的工具只是具有公共方法的已編譯的類)

一個通用的、經過測試的、隨時可用的工具庫

要把 VelocityViewServlet 集成到 Web 應用程序中,可以看一看示例 velview Web 應用程序(在 webapps\velview 目錄中)。該應用程序包括本文中所討論的那些模板。此外,它還顯示了請求、會話以及 servlet 上下文對象的屬性。集成的步驟如下:

首先要保證 velocity-tools-view.jar 文件在應用程序的 lib 目錄中。當然,這個 velocity JAR 文件也應該在那兒。

在部署描述符 web.xml 文件中,包括 VelocityViewServlet 。初始化參數是一個工具箱描述 XML 文件。該 servlet 映射為處理所有擴展名為 .vm 的文件,如清單 20 所示:

清單 20. VelocityViewServlet 的 Tomcat 部署描述符(web.xml)

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
   "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
  <servlet>
   <servlet-name>velocityView</servlet-name>
   <servlet-class>org.apache.velocity.tools.view.servlet.VelocityViewServlet</servlet-class>
   <init-param>
    <param-name>org.apache.velocity.toolbox</param-name>
    <param-value>/WEB-INF/toolbox.xml</param-value>
   </init-param>
  </servlet>
  <servlet-mapping>
   <servlet-name>velocityView</servlet-name>
   <url-pattern>*.vm</url-pattern>
  </servlet-mapping>
</web-app>

該例子的工具箱描述符(toolbox.xml)文件中,包含了兩個來自 Velocity 工具庫的通用工具可以在模板 DateTool 和 MathTool 中訪問。這兩個工具使我們能夠格式化日期和時間信息,並在模板中執行浮點運算,如清單 21 所示:

清單 21. 包括 DateTool 和 MathTool 的工具箱描述符

<?xml version="1.0"?>
<toolbox>
  <tool>
   <key>date</key>
   <scope>application</scope>
   <class>org.apache.velocity.tools.generic.DateTool</class>
  </tool>
<tool>
  <key>math</key>
  <scope>application</scope>
  <class>org.apache.velocity.tools.generic.MathTool</class>
</tool>
...

在 VelocityViewServlet 中有一組常用的標准工具,如表 1 所示:

表 1. VelocityViewServlet 中的標准工具

工具名 描述 LinkTool 處理 URI。該工具經常會用到,如果在模板中創建可點擊的鏈接就要用到該工具,可以生成依賴於上下文的 URI 部分。 CookieTool 使模板能夠創建或訪問浏覽器緩沖的 cookie。 ParameterParser 簡化後面收到的請求參數的解析。

還有兩個高度專門化的、不那麼常用的工具,如表 2 所示:

表 2. 專門的 VelocityViewServlet 工具

工具名 描述 ViewRenderTool 使模板能夠解析包含 VTL 的字符串。 AbstractSearchTool 提供了一種骨架工具(必須使用自定義的 Java 代碼來擴展),以便實現在線搜索和搜索結果分頁。

您可以使用 http://localhost:8080/velview/variables.vm URL 測試 velview 應用程序。您應該打開模板源代碼看一看所用的 Velocity 引擎、 LinkTool 和 CookieTool 。

與 Struts 框架的互操作

Struts 是一種構造基於 MVC 模型的框架的流行 Web 應用程序。Struts 默認的視圖組件技術是 JSP 技術。但是,可以很容易把 Velocity 集成進來作為視圖組件。圖 1 說明了 Velocity 的這種具體應用:

圖 1. Velocity 與 Struts MVC 框架集成

重要的是要看到,在這種結合中 Velocity 並沒有代替 JSP 技術。相反,JSP 技術和 Velocity 模板可以協同工作。集成 Velocity 需要配置 VelocityViewServlet 以便處理 .vm 模板,就像 部署 VelocityViewServlet 部分所講的那樣。這意味著.jsp 文件將繼續由容器(即 Tomcat 5 中的 Jasper)處理,而任何 .vm 模板則傳遞給 Velocity。

Velocity Tools 子項目中的 VelocityStruts 組件包含集成 Velocity 與 Struts 的所有功能。VelocityStruts 提供了一組專用的 Velocity 工具,用於訪問 Struts 專有的資源和 Velocity 模板中的信息。表 3 列出了最常用的工具:

表 3. 用於 VelocityStruts 集成的工具

工具名 描述 StrutsLinkTool 針對 Struts 的 LinkTool 專用版本,提供了 setAction() 和 setForward() 訪問預先配置的活動映射。 FormTool 訪問 Struts 的表單 beans。 ErrorsTool 處理 Struts 錯誤消息,包括對國際化的支持。 MessageTool 提供對 Struts 國際化支持的訪問,尤為特別的是依賴於語言的消息資源。

還有一組工具專用於 Struts 1.1 中的新特性,如表 4 所示:

表 4. 專用的 Struts 1.1 訪問工具

工具名 描述 SecureLinkTool 用於 Struts 1.1 的安全鏈接(SSL)擴展。 ActionMessagesTool 提供對 Struts 1.1 新對象 ActionMessages 的訪問。 TilesTool 提供對 Struts 1.1 Tiles 擴展支持的訪問。 ValidatorTool 提供對 Struts 1.1 Validator 擴展的訪問,生成代碼驗證表單輸入字段。

在 webapps\struts-example 目錄中可以找到一個例子,使用 Struts 而非 JSP 技術創建 Struts 頁面。本例中我們使用 Struts 取代了實例 Web 應用程序所發布的第一個標題頁,您可以試著改變其他的頁面。下面列出了操作的步驟。

把 Velocity 庫復制到 Struts 示例應用程序下的 WEB-INF\lib 目錄中。要使用 Tomcat 5(5.0.16 是撰寫本文時的最新版本)和 Struts 1.1,需要把以下 JAR 文件復制到 webapps\struts-example\WEB-INF\lib 目錄中:

velocity-tools-1.1-beta1.jar

velocity-1.4-rc1.jar

然後在 Struts 配置文件( WEB-INF\struts-config.xml ),把 Struts 動作映射設置為轉向 index.vm 文件而不是 index.jsp 文件,如清單 22 所示:
清單 22. 把 Struts 動作轉向 index.vm

<action  path="/logoff"
         type="org.apache.struts.webapp.example.LogoffAction">
    <forward name="success"       path="/index.vm"/>
   </action>

在部署描述符 WEB-INF\web.xml 文件中配置 VelocityViewServlet 處理 .vm 文件。同樣把歡迎文件設為 index.vm 而非 index.jsp,如清單 23 所示:
清單 23. 改變 struts 示例 Web 應用程序的部署描述符

<!-- Action Servlet Configuration -->
  <servlet>
   <servlet-name>action</servlet-name>
   <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
   <init-param>
    <param-name>config</param-name>
    <param-value>/WEB-INF/struts-config.xml,
    /WEB-INF/struts-config-registration.xml</param-value>
   </init-param>
   <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet>
   <servlet-name>velocity</servlet-name>
   <servlet-class>org.apache.velocity.tools.view.servlet.VelocityViewServlet
   </servlet-class>
   <init-param>
    <param-name>org.apache.velocity.toolbox</param-name>
    <param-value>/WEB-INF/toolbox.xml</param-value>
   </init-param>
   <init-param>
    <param-name>org.apache.velocity.properties</param-name>
    <param-value>/WEB-INF/velocity.properties</param-value>
   </init-param>
  </servlet>
  <!-- Action Servlet Mapping -->
  <servlet-mapping>
   <servlet-name>action</servlet-name>
   <url-pattern>*.do</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
   <servlet-name>velocity</servlet-name>
   <url-pattern>*.vm</url-pattern>
  </servlet-mapping>
  <!-- The Welcome File List -->
  <welcome-file-list>
   <welcome-file>index.vm</welcome-file>
  </welcome-file-list>

最後,把 toolbox.xml 和 velocity.properties 文件從本文的源代碼下載中移動到 WEB-INF 目錄下。

新的 index.vm 文件如清單 24 所示,可以把它與原來的 index.jsp 文件比較。

清單 24. 通過使用 index.vm Velocity 模板與 Struts 互操作

<html>
<head>
<title>$msg.get("index.title")</title>
</head>
<body bgcolor="white">
#if ( !$application.database)
  <font color="red">
   ERROR: User database not loaded -- check servlet container logs
   for error messages.
  </font>
  <hr>
#end
<h3>$msg.get("index.heading")</h3>
<ul>
<li>
<a href="$link.setURI("editRegistration.do").addQueryData("action","Create")">
$msg.get("index.registration")
</a>
</li>
<li>
<a href="$link.setURI("logon.jsp")">
$msg.get("index.logon")
</a>
</li>
</ul>
<p>&nbsp;</p>
<a href="$link.setURI("tour.do")">
<font size="-1">$msg.get("index.tour")</font>
</a>
<p>&nbsp;</p>
<img src="$link.setURI("powered-by-logo.gif")" alt="Powered by Velocity"/>
</body>
</html>

在 index.vm 中,整個模板都使用 $msg 內的消息工具訪問 Struts 的地域有關的國際化資源。通過對包含國際化字符串的資源包的本地化更改,這種方法避免了模板中的多數硬編碼字符串。

您可以使用 VTL 的條件指示符 #if 直接檢查在 servlet 上下文中是否存在數據庫屬性。$application 引用可用於訪問 servlet 上下文中的任何屬性( $request 、 $response 和 $session 也可用於訪問其他 Servlet API 對象的屬性)。

LinkTool 的 setURI() 方法用於生成服務器端到 Struts 動作和“Powered by Velocity”標志圖片的 URI 鏈接。注意,這裡使用 LinkTool 的 addQueryData() 方法向結果 URI 種增加附加的動作信息。

要測試該 Velocity 頁面,您可以啟動 Tomcat 5 並訪問 http://localhost:8080/struts-example/ URL。注意它的結果與原來的 JSP 版本完全一致。

結束語

Velocity 模板處理程序可以直接集成到 Java 語言應用程序中,立即提供報告生成或者模板處理的功能。

將模板引擎擴展到 Web 應用程序,可以使用 VelocityServlet 處理動態生成 HTML 輸出的 Velocity 模板。Velocity 工具項目對使用 VelocityViewServlet 組件化 Web 層應用程序開發提供了更多的支持。VelocityViewServlet 以模板為基礎為基於 Web 的 UI 構造提供了方便的視圖層。

在使用 MVC 模型框架設計復雜的 Web 應用程序時,Velocity 作為一種視圖/模板化技術——以 VelocityViewServlet 的形式——可以很方便地插入到框架中。對於流行的 Jakarta Struts MVC 框架,Velocity 可以與基於 JSP 的視圖技術協作,也可以和選擇的任何模型技術進行交互。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved