大多數(shù)程序都需要輸出一些文本,比如郵件消息、Html文件或控制臺(tái)輸出。但是,計(jì)算機(jī)本質(zhì)上只能處理二進(jìn)制數(shù)據(jù),程序員必須讓軟件來(lái)生成可理解的文本。在這篇文章中,我要介紹的是在生成和輸出文本時(shí),為何使用模板引擎能夠節(jié)省時(shí)間。你將了解模板的優(yōu)點(diǎn),如何針對(duì)不同的情形創(chuàng)建高效的模板。和System.PRintln說(shuō)再見!
雖然程序員可以很輕松地編寫出輸出文字信息的代碼(因?yàn)檫@究竟是從Hello World范例學(xué)到的第一件事情),但通常而言,程序員不是寫作或組織文字信息(如郵件)的最佳人選。因此,我們經(jīng)常讓市場(chǎng)部門或公關(guān)部門去做那些事情。但遺憾的是,即使對(duì)于最普通的郵件,編寫者也經(jīng)常依靠程序輸出來(lái)完成任務(wù)。無(wú)論是對(duì)于郵件編寫者還是程序員,這種合作方式都很輕易帶來(lái)誤解和造成失誤。
請(qǐng)看一個(gè)例子:一個(gè)java程序從某個(gè)數(shù)據(jù)源收集一些客戶信息,通過email給公司的每一個(gè)客戶發(fā)送帳戶余額信息。下面是完成這個(gè)任務(wù)的Java程序(完整的示例程序代碼可以從本文最后下載):
for (int i=0; i { Customer customer = (Customer)customers.get(i); StringBuffer message = new StringBuffer(); message.append ("尊敬的先生/女士: "); message.append (customer.getCustName()); message.append ("/n"); message.append ("/n"); message.append ("您的帳戶余額是 "); message.append (customer.getAccountTotal()); message.append ("/n"); message.append ("/n"); message.append ("致禮!"); message.append ("/n"); message.append ("某某裝飾品公司"); // 發(fā)送email mm.sendMail (customer.getFirstName(), customer.getEmail(), "Account", message.toString()); }
上面的例子可謂發(fā)送消息最差勁的方法之一。由于消息嵌入到了程序代碼之中,假如沒有程序員的幫助,其他人幾乎不可能對(duì)消息進(jìn)行編輯。同時(shí),即使對(duì)于專業(yè)的程序員,假如他不了解代碼,要進(jìn)行編輯也很困難。假如你預(yù)見了這些麻煩,把代碼寫成下面這種形式:
static public final String STR_HELLO="尊敬的先生/女士: "; static public final String STR_MESSAGE="您的帳戶余額是 "; static public final String STR_BEY="致禮!/n某某裝飾品公司";
假如說(shuō)上述代碼使得消息編輯更輕易,那么這種幫助也不會(huì)很多。很難要求一個(gè)不搞程序設(shè)計(jì)的人理解static和final的含義。此外,假如要改變消息的結(jié)構(gòu),上面這種代碼也不夠靈活。例如,人們可能要求你在郵件消息中加入更多來(lái)自數(shù)據(jù)源的信息,這時(shí),你就得修改構(gòu)造郵件的代碼,或許還要添加更多的static final String對(duì)象。
模板簡(jiǎn)介
從文本文件裝入消息文本可以解決部分問題——但不能提供動(dòng)態(tài)內(nèi)容,而這對(duì)于系統(tǒng)來(lái)說(shuō)是很重要的。你需要有一種方法把動(dòng)態(tài)內(nèi)容插入到預(yù)先編寫好的文本消息。但是,假如使用某種文本模板引擎,它就能夠幫助你完成所有復(fù)雜的工作。
模板引擎解決了把動(dòng)態(tài)內(nèi)容插入文本消息的問題。使用模板引擎時(shí),我們不再把消息直接嵌入程序,而是創(chuàng)建一個(gè)包含文本內(nèi)容的簡(jiǎn)單文本文件,稱為“文本模板”。模板引擎解析文本模板,借助一些簡(jiǎn)單的模板指令,把動(dòng)態(tài)內(nèi)容插入模板輸出結(jié)果。
我選擇的模板引擎是Jakarta Project的Velocity,但你可以任意選擇其他許多模板引擎之一。Velocity和WebMacro或許是當(dāng)前功能最豐富、最受歡迎的兩個(gè)引擎,而且兩者都按照源代碼開放協(xié)議免費(fèi)提供。雖然我在本文例子中使用Velocity,你可以方便地把這些例子移植到不同的模板引擎,只需遵照目標(biāo)引擎的語(yǔ)法即可。
我們來(lái)看看用Velocity完成的email程序例子。要編譯和運(yùn)行修改后的程序,你必須下載Velocity并把它加入到classpath。假如要讓email部分也能正常運(yùn)行,你還需要JavaMail。
for (int i=0; i<customers.size(); i++) { Customer customer = (Customer)customers.get(i); // 創(chuàng)建一個(gè)環(huán)境,并加入所有的對(duì)象 VelocityContext context = new VelocityContext(); context.put ("CustName",customer.getCustName()); context.put ("total", new Double (customer.getAccountTotal())); context.put ("customer", customer ); // 解析模板,生成結(jié)果字符串 StringWriter message = new StringWriter(); template.merge(context, message); // 發(fā)送email mm.sendMail (customer.getFirstName(), customer.getEmail(), "Account", message.toString()); }
首先,你應(yīng)該理解上面的Java源代碼。這里我們不再象第一個(gè)例子那樣生成文本,上面的代碼引用一個(gè)稱為“Velocity模板”的文本文件,然后把結(jié)果發(fā)送給收件人。Velocity模板可以是任何文本文件,但一般它包含一些用來(lái)插入動(dòng)態(tài)內(nèi)容的指令。
和VelocityContext相關(guān)的部分是上述代碼中最值得注重的地方。VelocityContext提供了Java程序和Velocity文本模板之間的連接,而Velocity文本模板可以由其他人來(lái)編寫。在模板中,所有加入到VelocityContext的對(duì)象都可以通過put()方法第一個(gè)參數(shù)指定的名字訪問。為了解其工作過程,請(qǐng)看下面的模板文件:
尊敬的先生/女士: $CustName您的帳戶余額是 $total致禮!某某裝飾品公司
Velocity引擎讀取模板文件時(shí),它直接輸出文件中所有的文本,但以$字符開頭的除外。$符號(hào)標(biāo)識(shí)著一個(gè)位置,在模板的輸出結(jié)果中,對(duì)象的值應(yīng)該插入到$符號(hào)所指示的位置。例如,Java代碼中有一個(gè)context.put ("CustName",customer.getCustName())語(yǔ)句,當(dāng)Velocity模板引擎解析并輸出模板的結(jié)果時(shí),模板中所有出現(xiàn)$CustName的地方都將插入客戶的名字;即,被加入到VelocityContext的對(duì)象的toString()方法返回值將替代Velocity變量(模板中以$開頭的變量)。
模板引擎中最強(qiáng)大、使用最頻繁的功能之一是它通過內(nèi)建的映像(Reflection)引擎查找對(duì)象信息的能力。這個(gè)映像引擎答應(yīng)用一種方便的Java“.”類似的操作符,提取任意加入到VelocityContext的對(duì)象的任何公用方法的值,或?qū)ο蟮娜我鈹?shù)據(jù)成員。映像引擎還帶來(lái)了另外一個(gè)改進(jìn):快速引用JavaBean的屬性。使用JavaBean屬性的時(shí)候,我們可以忽略get方法和括號(hào)(欲知具體信息,請(qǐng)參考模板引擎的說(shuō)明文檔)。請(qǐng)看下面這個(gè)模板的例子。由于在前面的Java代碼示例中,我把Customer對(duì)象加入到了VelocityContext,所以我可以把模板改寫成下面這種形式:
尊敬的先生/女士: $customer.CustName您的帳戶余額是 $customer.AccountTotal致禮!某某裝飾品公司
除了替換變量之外,象Velocity和WebMacro這類高級(jí)引擎還能做其他許多事情。它們有用來(lái)比較和迭代的內(nèi)建指令(盡管比較和迭代功能是兩個(gè)模板引擎之間的共同點(diǎn),但它們的語(yǔ)法差異很大,不能完全兼容。在選擇模板引擎或者更換模板引擎時(shí),務(wù)必注重這一點(diǎn))。
舉一個(gè)例子。十二月份,你的老板想要向所有的客戶發(fā)一個(gè)圣誕節(jié)問候的email。你可以把這個(gè)消息加入到模板,以后再刪除它。但這樣的話,你得在新年那一天上班工作,以便刪除圣誕問候消息。
一種更好的辦法是指示模板何時(shí)顯示圣誕問候消息。為此,你首先要把當(dāng)前的月份加入到VelocityContext:
int month = (new GregorianCalendar()).get(Calendar.MONTH); // 把month值加1,因?yàn)樗鼜?開始計(jì)算 context.put ("month", new Integer(month+1) );
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注