我用JSP和ASP編程已經有一段頗長的時間了,在這兩種伺服器端的程式解決方案中,我越來越覺得JSP的功能比ASP強大得多。我為什麼要把JSP選作首選伺服器端web應用程式開發工具呢?當然,JSP迷人的特性和功能不少,但JSP的標籤庫是讓我做出這個決定的最重要誘因之一。
為什麼要這樣說呢?原因有兩個面向:維護和開發的速度。伺服器端腳本語言其實就像是開發Internet的熔爐。在一個伺服器頁面上,你可以很方便地混合各種不同的腳本方法和物件。這種頁面簡直就是建築Web的混凝土。正是這種「材料」的混合給予了伺服器端腳本強大的資訊處理能力。它可以讓伺服器端程式設計人員開發出動態的、靈活的Web頁面。但是,另一方面,腳本的自由混合也有其缺點,那就是維護起來非常麻煩,特別是隨著專案規模的不斷增長而顯得尤其嚴重。更糟的是,隨著程式碼的複雜性增加,開發的速度就會變慢,不利於開發中等和大型的web應用,許多中等規模或者大型的伺服器端Web應用程式很晚才得以推出而且成本也無法控制。此外,一旦開發完,網站還要找合格的程式設計師來維護這些相當複雜的程式碼,結果讓這些程式設計師成為了一般的Web設計人員,伺服器端應用程式在最終的圖形設計和實現這兩方面上就弱化了。
為了克服這個問題,ASP引進了COM物件技術,而JSP則提供了J2EE作為對策。這些解決方案都是建立在集中的、可重複使用程式碼庫的機制之上。但是,他們使用起來可就太難了,學習所耗費的時間也很多。還有,這些解決方案並沒有減少建立混亂程式碼的誘惑,結果,我們只能組織起大型的、內部結構良好的開發團隊來使用這些技術。對於中等的項目來說,通常都較少使用這樣的方法,但事實上,中等的web應用程式才是最多的。因此,許多專案都不得不使用一個不符合它們所需的開發和維護環境。
幸好,JSP提供了一個解決這個問題的更好的方法。標籤庫(Tag libraries)提供了一個建立可重複使用程式碼區塊的簡單方式。一旦標籤庫設計好,它就可以在許多專案中再次使用。更方便的是,與COM和J2EE不同,只要你懂得寫JSP,你無需學習任何其它的技巧就可以建立一個標籤庫!最後,標籤庫也改進了Web應用程式的維護性。這種對維護性的改進表現在:輕易地在JSP頁面上就實現了基於XML的可自訂介面。結果可想而知,Web設計人員可以建立JSP Web應用程式而無需知道JSP是怎麼回事。這樣一來,Web開發就成為一項非常有效率的團隊開發任務了。 JSP程式設計師可以建立客製化的標籤和後端程式碼模組,而Web設計人員則可以使用客製化標籤並且全力專注於Web設計本身。標籤庫解決了程式碼混亂的問題,而且做得乾淨又漂亮(事實上,XML才是解決這些問題的本質所在,但是標籤庫還是起到了相當關鍵的作用)。
什麼是標籤庫?
JSP標籤庫(也稱為自訂標籤庫)可看成是一種透過JavaBean產生基於XML的腳本的方法。從概念上講,標籤就是很簡單且可重複使用的程式碼結構。比方說,在我們最新發布的JSPKit(在JSP Insider內)中,使用XML標籤實現了對XML文件的輕鬆存取。請看以下的清單A。
清單A:執行XML/XSL 轉換的範例標籤及其所在的HTML頁面
<%@ taglib uri=" http://www.jspinsider.com/jspkit/JAXP " prefix="JAXP"%>
<JAXP:TransformerTag>
<JAXP:XMLFile>c:/xml/example.xml</JAXP:XMLFile>
<JAXP:XSLFile>c:/xml/example.xsl</JAXP:XSLFile>
</JAXP:TransformerTag>
以上的範例使用了簡單的標籤來存取處在幕後的更強大程式碼,標籤部分的語句首先裝載了一個XML文件,然後應用了一個XSL檔案來將XML檔案中的內容轉換成某個表現格式,並傳送給客戶端,這一切都只是用了一個很簡單的標籤。自訂標籤使得JSP專案中很容易建立重複使用的開放原始碼模組,而你所需要的只是標籤庫和它的文件說明。
標籤庫的重要特性
1.易於安裝在多個專案上標籤很容易從一個JSP專案遷移到其他專案。一旦建立了一個標籤庫,則只需要將所有的東西打包為一個JAR文件,你就可以在任何的JSP專案中重新使用。因為標籤可以重新使用,標籤庫可以輕鬆地用於你自己的項目,所以標籤庫越來越通行。目前,最好的標籤資源可以在JSPTags.com這個網站找到。
2.擴展JSP 標籤庫可以具備JSP規範(JSP 1.2)中的任何特性和功能,你可以無限制地擴展和增加JSP的功能,而無需要等待下一版本JSP的出現。例如,你對JSP的include呼叫不太滿意。你可以建立自己的include標籤,該標籤執行的是你自己的規範。
3.容易維護
標籤庫使得JSP的web應用程式非常容易維護,原因有:
(1)標籤應用簡單,對任何人而言都很容易使用、易於理解。
(2)所有的程式邏輯程式碼都集中在的標籤處理器和JavaBeans。這意味著你在升級程式碼時,無需要對每個使用該程式碼的頁面進行修改,你只需要修改集中的程式碼檔案即可。
(3)如果需要加入新的功能,你也不需要修改任何已經存在的頁面,可以在標籤中加入額外的屬性,從而引進新的行為,而其它舊的屬性不變,這樣所有舊的頁面還可以正常工作。 例如你有一個讓所有文字變藍的標籤:
<BlueText>My Text</BlueText>
但在後來專案中,你又想讓藍色變暗。你可以保留原有的標籤,只要為其增加一個新的屬性:shade ,如下:
<BlueText shade="teal">My Text</BlueText>
所有舊的標籤仍然可以產生藍色的文本,但現在你可以使用同一標籤來產生變暗的藍色文本了。
(4)標籤提升了程式碼的重用性。那些經過多次測試和使用的程式碼肯定具有更少的bug。所以,使用客製化標籤的JSP頁面也同樣有更少的缺陷,維護起來自然方便多了。
4.快速的開發時間標籤庫提供一個簡單的方式來重複使用程式碼。在伺服器端的語言中,其中一個標準的重用程式碼方式是使用模板。相對於使用範本庫,標籤庫是更好的解決方案。使用範本庫,你必須為每個專案修改範本或且建立嚴格的介面,而標籤庫則沒有這些限制,並且擁有所有物件導向的好處,可以做到靈活和更有擴展性,而且,透過重用程式碼,你可以花更少的時間來做開發,更多的時間可以用在設計你的web應用程式上。標籤庫的介面也很簡單,非常容易做插入、使用和調試。
標籤的組成結構
雖然標籤庫非常容易使用,不過要建立一個標籤庫的內部實作機制還是相當複雜的,起碼比建立一個簡單的JavaBean複雜。這個複雜是來自於標籤庫是由幾個部分構成的。不過,你只需要掌握了Java和JSP的知識就夠了。
一個簡單的標籤由下面的元素構成:
1. JavaBean:為了得到Java與生具來的物件導向的好處,可重複使用的程式碼應該放到一個獨立的程式碼容器中,也就是JavaBean。這些JavaBeans並不是標籤庫必不可少的一部分,但它們是標籤庫用來執行所指派任務的基礎程式碼模組。
2.標籤處理器:標籤處理器是標籤庫的真正核心。一個標籤處理器(tag handler)引用它所需要的任何外部資源(JavaBean)並且負責存取JSP頁面的資訊(PageContext物件)。而JSP頁面則把頁面上設定的標籤屬性和標籤體中的內容都傳遞給標籤處理器,當標籤處理器完成其處理過程後,它就會把處理後的輸出結果回送給JSP頁面做進一步處理。
3.標籤庫描述符(TLD文件):這是一個簡單的XML文件,它記錄標籤處理器的屬性、資訊和位置等資訊。 JSP容器透過這個檔案來得知從哪裡及如何呼叫一個標籤庫。
4. Web網站的web.xml檔案:這是Web網站的初始化文件,在這個檔案中,需要定義了Web網站中使用的自訂標籤,以及用來描述每個自訂標籤的tld檔案。
5.發布檔案(WAR或JAR檔案):如果你想重複使用自訂標籤的話,你需要一個方法來將它由一個專案遷移到其他專案中去。將標籤庫打包為一個JAR檔案是一個簡單且有效的方式。
6. JSP頁面上的標籤庫聲明:要在JSP頁面中的使用某個自訂標籤的話,需要使用標籤庫標示符在頁面上進行聲明。
看來要做的工作很多,剛開始用的時候當然會有點棘手,但其實不是很難。它的要點並不在於編碼,而是如何將各部分正確地組織起來。這種層次性的結構是很重要的,它令標籤的使用變得靈活且更容易轉移。更重要的事,這些層次可以讓整個建立標籤庫的過程都能透過JSP IDE(JSP的整合開發環境)自動完成。 JSP IDE更可以自動完成創建自訂標籤的大部分工作,而你自己則只需要負責建立程式碼和標籤處理器。
(注意:一個標籤處理器只定義一個自訂標籤;一個標籤庫是幾個處理相同任務的標籤處理器的集合)
建立你的第一個標籤
以下將一步一步地教你如何建立自訂的標籤,具體的例子是擴充JSP,令它擁有自己的HTML編碼功能。這個功能將所有的<和>字元用HTML程式碼來取代。它可以很容易地擴展為做其它的編碼處理。為了簡化,這個例子只解釋了建立自訂標籤的基本要素。
建立JavaBean
程式碼中的任何可重複使用部分都應該放到一個JavaBean中。這一點是很重要的。這樣你就可以在其他專案中重複使用這些程式碼了。由於任何放置在標籤處理器內的程式碼在標籤外都是不可以重複使用的,因此將可重複使用的程式碼部分獨立開來是很重要的。在這個例子總,為HTML編碼的邏輯是常用的,因此放到JavaBean中,請參考清單B
清單B:HTML編碼JavaBean
/* HTML_Format.java */
public class HTML_Format extends Object implements java.io.Serializable {
/** 建立新的HTML_Format */
public HTML_Format() {}
/** 將一個字串中所有的所有< 和> 字元以回應的HTML編碼取代*/
public String HTML_Encode(String as_data)
{
int li_len = as_data.length();
/*string buffer的長度比原來的字串長*/
StringBuffer lsb_encode = new StringBuffer(li_len + (li_len/10));
/* 循環取代全部的< 和> 字元*/
for( int li_count = 0 ; li_count < li_len ; li_count++)
{ String ls_next = String.valueOf(as_data.charAt(li_count));
if (ls_next.equals("<")) ls_next = "<";
if (ls_next.equals(">")) ls_next = ">";
lsb_encode.append( ls_next );
}
return( lsb_encode.toString() );
}
}
建立標籤處理器標籤處理器的程式碼請參考清單C:
清單C:HTML編碼標籤處理器
import java.io.IOException;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
public class HTML_FormatTag extends BodyTagSupport
{
/* 1) 在標籤結束時將會呼叫這個函數*/
public int doEndTag() throws JspTagException
{
try
{ /* 2)得到標籤中的文字*/
BodyContent l_tagbody = getBodyContent();
String ls_output = "";
/* 3)如果標籤體有文字,就處理它*/
if(l_tagbody != null)
{ HTML_Format l_format = new HTML_Format();
/* 3a) 將標籤體的內容轉換為一個字串*/
String ls_html_text = l_tagbody.getString();
ls_output = l_format.HTML_Encode(ls_html_text);
}
/* 4)將結果寫回資料流*/
pageContext.getOut().write(ls_output.trim());
}
catch (IOException e)
{ throw new JspTagException("Tag Error:" + e.toString());
}
/* 讓JSP繼續處理以下頁面的內容*/
return EVAL_PAGE;
}
}
這個處理很簡單,它包含有:
1.讀入位於開始和結束標籤間的文本
2.呼叫html編碼函數
3.將結果返回JSP頁面。
建立標籤描述符
我們需要描述自訂標籤以讓系統知道如何處理。此描述檔的後綴為.tld,TLD檔通常以標籤處理器命名,並存放在「/WEB-INF/」目錄之下。請參看清單D。
清單D:HTML編碼標籤描述器<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
" http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd ">
<TAGLIB>
<TLIBVERSION>1.0</TLIBVERSION>
<JSPVERSION>1.1</JSPVERSION>
<SHORTNAME>HTML_FormatTag</SHORTNAME>
<URI></URI>
<INFO>HTML Encoding Tag </INFO>
<TAG>
<NAME>HTMLEncode</NAME>
<TAGCLASS>HTML_FormatTag</TAGCLASS>
<INFO>Encode HTML</INFO>
</TAG>
</TAGLIB>
更新Web XML檔案
現在可以告訴JSP容器如何使用標籤庫了。為此要修改web.xml文件,具體來說是要在其中加入一個taglib的專案來註冊該標籤庫,並為標籤分配一個URI。 URI是Web網站上唯一套用於此特定標籤的索引。由於標籤今後也可能用在不同的Web網站上,所以你最好採用完整的URL和/或套件名字(package name)來保證這個唯一性。這個範例是簡化了,範例程式碼請參看清單E。
清單E:修改web.xml檔<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
" http://java.sun.com/j2ee/dtds/web-app_2.2.dtd ">
<WEB-APP>
<TAGLIB>
<TAGLIB-URI>
HTMLEncode
</TAGLIB-URI>
<TAGLIB-LOCATION>
/WEB-INF/HTML_FormatTag.tld
</TAGLIB-LOCATION>
</TAGLIB>
</WEB-APP>
使用新的標籤
自訂的標籤設定好後,就可以用在你的JSP頁面上了。要做到這一點,只需要在頁面上使用taglib指示指令聲明所要採用的標籤。標籤透過其唯一的URI被索引,然後被分配給一個名字空間前綴(prefix)。這前綴並沒有什麼特別的意義,只要它不與其它的名字空間衝突便可,可以任意。請參考以下的清單F和G。
清單F:在一個JSP頁面上使用HTML編碼標籤
<%@ taglib uri="HTMLEncode" prefix="Examples" %>
<PRE>
<?XML:NAMESPACE PREFIX = Examples /><Examples:HTMLEncode>
< Hello , Simple sample >
</Examples:HTMLEncode>
</PRE>
清單G:範例程式碼的輸出< Hello , Simple sample >
which displays as:
< Hello , Simple sample >
透過這個標籤,我就將該頁面的所有程式碼編碼了。所有的自訂標籤都是在伺服器上處理的。這意味著你將不會在輸出的頁面上看到自訂的標籤。
正如你所看到的那樣,建立標籤並非難事。最麻煩的是學習標籤處理器的整個細節。這是一個很強大的功能,我們不過是觸及了皮毛。由於這個過程需要採取的步驟很多,所以剛入門的JSP程式設計師可能在建立標籤的時候會覺得很困惑。
結論
標籤庫是JSP最重要的特性之一,它也處於不斷的發展中。它的確是一個新事物,因此還沒有被廣泛採用,不過自訂標籤庫已經剝去了它的神秘面紗,越來越多的開發者也開始關注和使用它了。在2001年末,可預料標籤庫將是許多JSP專案中的一個很常見的特性。
在這篇文章中只簡要地討論了標籤庫的好處。標籤庫實際上還有許多其它強大的功能。標籤庫促使JSP開發進入了前所未有的新天地。對JSP開發人員來說這確實是一種很令人振奮的新技術,因為他們得到了一個可將JSP轉到各個應用並且建立任何類型web應用的工具。標籤庫讓JSP變成了最豐富、最具動態開發能力的、強大的Web程式設計環境。它的功能只受我們的想像和創造力限制。