CHAPTER 5 構(gòu)建Hello World示例
目前,你已經(jīng)對Velocity有了一個很好的理解,并且理解了MVC是如何工作的,同時也搭建一個Velocity的工作環(huán)境,是時候開始學(xué)習(xí)如何Velocity了。正如你所期望的一樣,第一個示例就是Hello World。
Hello World!
首先,你需要確定HTML頁面的Hello World模板和在頁面上顯示些什么信息。如果我們僅僅簡單的輸出“Hello World”,這就不能很好體現(xiàn)Velocity的特性。因此,我們準(zhǔn)備生成一個模板,輸出內(nèi)容為:“Hello World, Sam is Here”,在這里,“Sam”用的是引用值。
現(xiàn)在,你已經(jīng)知道了頁面需要輸出的內(nèi)容,接下來,你需要和JAVA開發(fā)者一起討論并確定頁面所需要引用對象的名稱(此處的引用對象是“Sam”),在這里我們將這個引用對象的名稱約定為“name”。在構(gòu)建Hello World示例時,你需要考慮以下三個版本:
■ 不使用上下文的Velocity模板
■ 使用上下文的Velocity模板
■ 使用WEB的Velocity模板
如果你已經(jīng)非常熟悉服務(wù)器端語言,比如PHP,你或許會非常驚奇,在Velocity模板被瀏覽時,我們?yōu)槭裁床挥懻?/span>WEB服務(wù)器的解釋程序。這是因?yàn)?/span>Velocity并不含解釋程序,它是純JAVA語言,屬性編譯運(yùn)行方式,而非解釋運(yùn)行方式。所有在模板和上下文之間的合并處理都是通過JAVA代碼來完成的。這些JAVA代碼可能存在于Servlet中,也可嵌入JSP或應(yīng)用程序中。
在WEB中使用Velocity時,很多情況下是使用Servlet來處理模板轉(zhuǎn)換工作的。
不使用上下文的Velocity模板
Hello World示例代碼見Listing 5.1,它使用Velocity指令語句#set來為模板中引用指定一個值(在模板中使用),同時使用嵌入Hello World文本的$name指令來引用#set指定的值。
這個示例比較容易理解,在Velocity對模板進(jìn)行解析時,如果是普通的文本,則忽略,直接輸出;當(dāng)遇到#set指令時,它就創(chuàng)建一個名叫$name的內(nèi)部變量(在模板文件中指定的),并賦值為"Sam"(在模板文件中指定的);接著,程序?qū)⒅苯虞敵?/span>“Hello World”文本;在系統(tǒng)處理到$name引用時,系統(tǒng)將嘗試在上下文中查找一個名叫$name的對象,如果在上下文中沒有匹配的對象,系統(tǒng)將嘗試匹配之前用#set創(chuàng)建的引用。
#set( $name = "Sam" )
Hello World, $name is Here
Listing 5.1 The Velocity Hello World template.
當(dāng)然,僅僅擁有一個模板是不能工作的,你還需要一個把模板和上下文合并,并輸出給用戶的途徑。Listing 5.2顯示了一個獨(dú)立應(yīng)用需要用到的相關(guān)代碼。
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 {
//從命令行參數(shù)獲取模板文件,并進(jìn)行初始化操作
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應(yīng)用程序一樣,這個示例需要導(dǎo)入一些JAVA包,前面5個導(dǎo)入了運(yùn)行Velocity需要的類。當(dāng)?shù)谝淮芜\(yùn)行這個示例時,需要在命令行提供模板文件名這個參數(shù)。如:
java Example example.vm
回頭查看Listing 5.2的模板示例我們可以看到,模板文件的名稱被放置到命令行上,并傳遞給新創(chuàng)建的示例對象。在這里,首先需要完成Velocity引擎的初始化操作,示例利用一個獨(dú)立模式關(guān)聯(lián)應(yīng)用程序和Velocity引擎,這就意味著僅有一個靜態(tài)引擎是可用的。記住這個事實(shí)很重要,因?yàn)槟憧隙ú幌M倏吹绞纠羞€有其他任何初始化引擎的代碼。
一旦引擎被初始化,就將從本地磁盤上加載模板。模板是通過Velocity引擎對象的getTemplate(String)方法進(jìn)行加載的,該方法的結(jié)果是調(diào)用了一個模板對象;另外,如果沒有找到,就會拋出異常。很重要的一點(diǎn)是,當(dāng)找不到模板文件或把模板文件解析成模板對象出錯時,異常將通過ResourceNotFoundException進(jìn)行拋出。當(dāng)讀取模板并進(jìn)行解析時出錯,也會拋出ParseErrorException異常。
當(dāng)模板被讀入到系統(tǒng)之后,你就可以開始處理輸出了。此處要注意的是,除了輸出到控制臺的方式外,還可以輸出為一個文件、一個套接字socket或其他的輸出。
在這個示例里,你已經(jīng)在應(yīng)用程序里使用了幾個不同的內(nèi)容:
■ Velocity—一個靜態(tài)對象,表現(xiàn)為Velocity引擎
■ Context—一個上下文對象
■ Template—一個模板對象,在從本地磁盤讀入Velocity模板文件時創(chuàng)建
■ Writer—一個BufferedWriter對象,用于向控制臺直接輸出(通過System.out流)。在輸出前,要核實(shí)BufferedWriter已經(jīng)正確進(jìn)行了初始化。之后,Velocity引擎通過使用模板對象的merge()方法(帶有兩參數(shù):一個上下文對象和一個BufferedWriter對象)來完成內(nèi)容合并。merge()方法帶有兩參數(shù):一個上下文對象和一個BufferedWriter對象,當(dāng)模板對象執(zhí)行merge()方法時,上下文被合并到模板文件中,同時用上下文中對應(yīng)的值替換模板中的腳本元素,完成輸出創(chuàng)建工作。
最后,沖洗(flush)和關(guān)閉輸出流。Figure 5.1 顯示了輸出結(jié)果。
Figure 5.1 Output from the Hello World example.
在這個示例里,我們將Listing 5.1中的模板內(nèi)容保存為一個文件,命名為helloworld.vm。在這里,擴(kuò)展名不限于VM,也可以是其他的擴(kuò)展名,目的是與其他文件進(jìn)行區(qū)別,比如:HTML或JSP,當(dāng)然,也完全可以是定義的,比如XX。另外,我們把Listing 5.2的內(nèi)容保存到一個名叫Example.java的文件中,并將其編譯成class文件。
javac Example.java
執(zhí)行示例的命令為
java Example helloworld.vm
如果Velocity引擎不能定位模板文件位置,將產(chǎn)生一個錯誤。
使用上下文的Velocity模板
在上一個示例里,我們通過#set指令來給$name引用指定值。但這樣做將限制Velocity的動態(tài)處理能力,比如,如果需要動態(tài)的更改用戶名稱,就成為一個不可能完成的任務(wù)。要想獲得這個能力,需要使用上下文對象,在第二個示例里,我們使用和Listing 5.1相同的模板,但刪除了#set指令這一行,只保留現(xiàn)在這一行:
Hello World, $name is Here
在JAVA代碼中找到下面這行代碼
VelocityContext context = new VelocityContext();
在其之后加上下面這行代碼:
context.put("name", "New Sam");
存儲這個文件,編譯和執(zhí)行它。你就將看到這樣的輸出“Hello World, New Sam is Here.”。現(xiàn)在讓我們試一試其他,打開這個應(yīng)用程序代碼,改變context.put的參數(shù)內(nèi)容。
context.put("names", "New Sam");
重新編輯并執(zhí)行。輸出結(jié)果為“Hello World, $name is here”,為什么會得到這個輸出?好,讓我們再仔細(xì)看一下context.put()語句。正如你在前面章節(jié)學(xué)到的一樣,Velocity像變魔法一樣把模板和上下文合并到一起,所有在模板的引用,比如$name必須和上下文對象中的關(guān)鍵字相匹配。因此,Velocity將嘗試在上下文對象中查找關(guān)鍵字“name”來與模板引用$name相匹配。如果匹配上了,則將上下文中關(guān)鍵字“name”中保存的值“New Sam”合并入模板并返回給用戶;如果在上下文中沒有找到對應(yīng)的關(guān)鍵字,引擎將直接把“$name”作為字符串返回,不進(jìn)行任何合并操作。
在這里,之所有輸出為“Hello World, $name is here”,是因?yàn)槲覀儼?/span>context.put()的關(guān)鍵字改成了“names”,也就是說在上下文中保存的是“names”關(guān)鍵字的值,Velocity引擎也就不能匹配模板的$name引用,所以Velocity引擎直接返回$name字符串。
使用WEB的Velocity模板
迄今為此,我們所做的兩個示例都是用于獨(dú)立的JAVA應(yīng)用程序。然而,當(dāng)把Velocity用于替代jSP時,你可能最期待的就是把Velocity用于WEB應(yīng)用程序。在這一節(jié)里,我們將看一看如何在Servlets里使用Velocity。關(guān)于這個主題的更多信息,詳見Chapter 12“在Servlets里使用Velocity”,Listing 5.3展示了一個用于在瀏覽器里顯示一個XML文檔的新模板。正如你所看到的一樣,這個模板有一些小的功能。
在之后的章節(jié)里,我們將檢驗(yàn)更多的模板語句。目前,你首先需要關(guān)注的第一個在#foreach和#next指令之間的語句。這些指令允許你創(chuàng)建一個基于某些引用(此處為$value)的循環(huán)。
<?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 向你展示了用于產(chǎn)生XML的servlet代碼。正如我們說及的一樣,我們將在Chapter 12詳細(xì)討論Servlets,這里我們只關(guān)注Velocity對象的創(chuàng)建和三個增加到里面的值。用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被放置到上下文對象中,就需要從本地磁盤上獲取用于顯示上下文信息的模板。現(xiàn)在不再使用模板對象的merge()方法進(jìn)行合并操作,而是簡單的返回模板。這個模板實(shí)際上不會直接返回給用戶,而是在后臺對“被返回來的”模板和上下文進(jìn)行合并處理,并返回給用戶一個XML的類型的內(nèi)容。在Figure 5.2里,你可以看到由Servlets和模板創(chuàng)建的XML輸出。如果需要,你也可以使用Velocity向用戶的瀏覽器輸出HTML。
Figure 5.2 The servlet and template example output.
本章小節(jié)和下章介紹
在這一章里,我們向你展示了如何用Velocity來書寫Hello World獨(dú)立應(yīng)用程序。你可以使用Velocity來開發(fā)獨(dú)立應(yīng)用程序和WEB應(yīng)用。在下一章里,我們將開始詳細(xì)介紹Velocity,并學(xué)習(xí)它與其他語言不一樣的特性。
posted on 2008-10-13 00:42 KINGWEE 閱讀(726) 評論(0) 編輯 收藏 所屬分類: Velocity