CHAPTER 5 構建Hello World示例
目前,你已經對Velocity有了一個很好的理解,并且理解了MVC是如何工作的,同時也搭建一個Velocity的工作環境,是時候開始學習如何Velocity了。正如你所期望的一樣,第一個示例就是Hello World。
Hello World!
首先,你需要確定HTML頁面的Hello World模板和在頁面上顯示些什么信息。如果我們僅僅簡單的輸出“Hello World”,這就不能很好體現Velocity的特性。因此,我們準備生成一個模板,輸出內容為:“Hello World, Sam is Here”,在這里,“Sam”用的是引用值。
現在,你已經知道了頁面需要輸出的內容,接下來,你需要和JAVA開發者一起討論并確定頁面所需要引用對象的名稱(此處的引用對象是“Sam”),在這里我們將這個引用對象的名稱約定為“name”。在構建Hello World示例時,你需要考慮以下三個版本:
■ 不使用上下文的Velocity模板
■ 使用上下文的Velocity模板
■ 使用WEB的Velocity模板
如果你已經非常熟悉服務器端語言,比如PHP,你或許會非常驚奇,在Velocity模板被瀏覽時,我們為什么不討論WEB服務器的解釋程序。這是因為Velocity并不含解釋程序,它是純JAVA語言,屬性編譯運行方式,而非解釋運行方式。所有在模板和上下文之間的合并處理都是通過JAVA代碼來完成的。這些JAVA代碼可能存在于Servlet中,也可嵌入JSP或應用程序中。
在WEB中使用Velocity時,很多情況下是使用Servlet來處理模板轉換工作的。
不使用上下文的Velocity模板
Hello World示例代碼見Listing 5.1,它使用Velocity指令語句#set來為模板中引用指定一個值(在模板中使用),同時使用嵌入Hello World文本的$name指令來引用#set指定的值。
這個示例比較容易理解,在Velocity對模板進行解析時,如果是普通的文本,則忽略,直接輸出;當遇到#set指令時,它就創建一個名叫$name的內部變量(在模板文件中指定的),并賦值為"Sam"(在模板文件中指定的);接著,程序將直接輸出“Hello World”文本;在系統處理到$name引用時,系統將嘗試在上下文中查找一個名叫$name的對象,如果在上下文中沒有匹配的對象,系統將嘗試匹配之前用#set創建的引用。
#set( $name = "Sam" )
Hello World, $name is Here
Listing 5.1 The Velocity Hello World template.
當然,僅僅擁有一個模板是不能工作的,你還需要一個把模板和上下文合并,并輸出給用戶的途徑。Listing 5.2顯示了一個獨立應用需要用到的相關代碼。
import org.apache.velocity.app.Velocity;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.Template;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import java.io.*;
import java.util.ArrayList;
public class Example {
//從命令行參數獲取模板文件,并進行初始化操作
public Example(String templateFile) {
try {
Velocity.init();
VelocityContext context = new VelocityContext();
Template template = null;
try {
template = Velocity.getTemplate(templateFile);
} catch(ResourceNotFoundException e2 ) {
System.out.println(
"cannot find template " + templateFile );
} catch(ParseErrorException e ) {
System.out.println(
"Syntax error in template : " + e);
}
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(System.out));
if ( template != null)
template.merge(context, writer);
writer.flush();
writer.close();
} catch( Exception e ) {
System.out.println(e);
}
}
public static void main(String[] args) {
Example t = new Example(args[0]);
}
}
Listing 5.2 The Velocity application without context. (continued)
和許多的JAVA應用程序一樣,這個示例需要導入一些JAVA包,前面5個導入了運行Velocity需要的類。當第一次運行這個示例時,需要在命令行提供模板文件名這個參數。如:
java Example example.vm
回頭查看Listing 5.2的模板示例我們可以看到,模板文件的名稱被放置到命令行上,并傳遞給新創建的示例對象。在這里,首先需要完成Velocity引擎的初始化操作,示例利用一個獨立模式關聯應用程序和Velocity引擎,這就意味著僅有一個靜態引擎是可用的。記住這個事實很重要,因為你肯定不希望再看到示例中還有其他任何初始化引擎的代碼。
一旦引擎被初始化,就將從本地磁盤上加載模板。模板是通過Velocity引擎對象的getTemplate(String)方法進行加載的,該方法的結果是調用了一個模板對象;另外,如果沒有找到,就會拋出異常。很重要的一點是,當找不到模板文件或把模板文件解析成模板對象出錯時,異常將通過ResourceNotFoundException進行拋出。當讀取模板并進行解析時出錯,也會拋出ParseErrorException異常。
當模板被讀入到系統之后,你就可以開始處理輸出了。此處要注意的是,除了輸出到控制臺的方式外,還可以輸出為一個文件、一個套接字socket或其他的輸出。
在這個示例里,你已經在應用程序里使用了幾個不同的內容:
■ Velocity—一個靜態對象,表現為Velocity引擎
■ Context—一個上下文對象
■ Template—一個模板對象,在從本地磁盤讀入Velocity模板文件時創建
■ Writer—一個BufferedWriter對象,用于向控制臺直接輸出(通過System.out流)。在輸出前,要核實BufferedWriter已經正確進行了初始化。之后,Velocity引擎通過使用模板對象的merge()方法(帶有兩參數:一個上下文對象和一個BufferedWriter對象)來完成內容合并。merge()方法帶有兩參數:一個上下文對象和一個BufferedWriter對象,當模板對象執行merge()方法時,上下文被合并到模板文件中,同時用上下文中對應的值替換模板中的腳本元素,完成輸出創建工作。
最后,沖洗(flush)和關閉輸出流。Figure 5.1 顯示了輸出結果。
Figure 5.1 Output from the Hello World example.
在這個示例里,我們將Listing 5.1中的模板內容保存為一個文件,命名為helloworld.vm。在這里,擴展名不限于VM,也可以是其他的擴展名,目的是與其他文件進行區別,比如:HTML或JSP,當然,也完全可以是定義的,比如XX。另外,我們把Listing 5.2的內容保存到一個名叫Example.java的文件中,并將其編譯成class文件。
javac Example.java
執行示例的命令為
java Example helloworld.vm
如果Velocity引擎不能定位模板文件位置,將產生一個錯誤。
使用上下文的Velocity模板
在上一個示例里,我們通過#set指令來給$name引用指定值。但這樣做將限制Velocity的動態處理能力,比如,如果需要動態的更改用戶名稱,就成為一個不可能完成的任務。要想獲得這個能力,需要使用上下文對象,在第二個示例里,我們使用和Listing 5.1相同的模板,但刪除了#set指令這一行,只保留現在這一行:
Hello World, $name is Here
在JAVA代碼中找到下面這行代碼
VelocityContext context = new VelocityContext();
在其之后加上下面這行代碼:
context.put("name", "New Sam");
存儲這個文件,編譯和執行它。你就將看到這樣的輸出“Hello World, New Sam is Here.”。現在讓我們試一試其他,打開這個應用程序代碼,改變context.put的參數內容。
context.put("names", "New Sam");
重新編輯并執行。輸出結果為“Hello World, $name is here”,為什么會得到這個輸出?好,讓我們再仔細看一下context.put()語句。正如你在前面章節學到的一樣,Velocity像變魔法一樣把模板和上下文合并到一起,所有在模板的引用,比如$name必須和上下文對象中的關鍵字相匹配。因此,Velocity將嘗試在上下文對象中查找關鍵字“name”來與模板引用$name相匹配。如果匹配上了,則將上下文中關鍵字“name”中保存的值“New Sam”合并入模板并返回給用戶;如果在上下文中沒有找到對應的關鍵字,引擎將直接把“$name”作為字符串返回,不進行任何合并操作。
在這里,之所有輸出為“Hello World, $name is here”,是因為我們把context.put()的關鍵字改成了“names”,也就是說在上下文中保存的是“names”關鍵字的值,Velocity引擎也就不能匹配模板的$name引用,所以Velocity引擎直接返回$name字符串。
使用WEB的Velocity模板
迄今為此,我們所做的兩個示例都是用于獨立的JAVA應用程序。然而,當把Velocity用于替代jSP時,你可能最期待的就是把Velocity用于WEB應用程序。在這一節里,我們將看一看如何在Servlets里使用Velocity。關于這個主題的更多信息,詳見Chapter 12“在Servlets里使用Velocity”,Listing 5.3展示了一個用于在瀏覽器里顯示一個XML文檔的新模板。正如你所看到的一樣,這個模板有一些小的功能。
在之后的章節里,我們將檢驗更多的模板語句。目前,你首先需要關注的第一個在#foreach和#next指令之間的語句。這些指令允許你創建一個基于某些引用(此處為$value)的循環。
<?xml version="1.0" encoding="ISO-8859-1" ?>
<list>
#foreach( $value in $list )
<number>$value</number>
#end
</list>
Listing 5.3 The servlet example template.
Listing 5.4 向你展示了用于產生XML的servlet代碼。正如我們說及的一樣,我們將在Chapter 12詳細討論Servlets,這里我們只關注Velocity對象的創建和三個增加到里面的值。用context.put("list", v)語句把整個Vector對象附屬到上下文中。
import java.util.Vector;
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.servlet.VelocityServlet;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.ParseErrorException;
public class VelocityServletExample extends VelocityServlet {
public Template handleRequest( HttpServletRequest request,
HttpServletResponse response,
Context context ) {
Vector v = new Vector();
v.add("one");
v.add("two");
v.add("three");
context.put("list", v);
Template template = null;
try {
template = getTemplate("displaylist.vm");
} catch( Exception e ) {
System.out.println("Error " + e);
}
return template;
}
}
Listing 5.4 The servlet code for our example.
一旦vector被放置到上下文對象中,就需要從本地磁盤上獲取用于顯示上下文信息的模板。現在不再使用模板對象的merge()方法進行合并操作,而是簡單的返回模板。這個模板實際上不會直接返回給用戶,而是在后臺對“被返回來的”模板和上下文進行合并處理,并返回給用戶一個XML的類型的內容。在Figure 5.2里,你可以看到由Servlets和模板創建的XML輸出。如果需要,你也可以使用Velocity向用戶的瀏覽器輸出HTML。
Figure 5.2 The servlet and template example output.
本章小節和下章介紹
在這一章里,我們向你展示了如何用Velocity來書寫Hello World獨立應用程序。你可以使用Velocity來開發獨立應用程序和WEB應用。在下一章里,我們將開始詳細介紹Velocity,并學習它與其他語言不一樣的特性。
posted on 2008-10-13 00:42 KINGWEE 閱讀(727) 評論(0) 編輯 收藏 所屬分類: Velocity