自訂JSP標籤(tag)淺議
最後更新:2017-02-28
來源:互聯網
上載者:User
js 因為版本變化的關係,這篇文章未必有普適性
看這篇文章之前應該先看Sun的文章並最好動手實踐之
http://java.sun.com/developer/technicalArticles/xml/WebAppDev3/
並且知道J2EE API文檔的位置在
http://java.sun.com/j2ee/sdk_1.3/techdocs/api/index.html
自訂Tag其實並不是一件很困難的事情,就是猛一接觸,不知道該從何下手。推薦先看看Sun公司的一篇文章,看完了,大致就有了一個印象。在這裡無意去翻譯這篇簡單的文章,而是從這篇文章展開去說說。要說明的一點就是sun的文檔中代碼都是完全可用的,但是因為排版問題,代碼的分行有些地方不正確,直接copy的時候要仔細整理一下代碼,否則有可能會通不過編譯,部署的時候會給你一大堆異常。
自訂Tag使用的包是javax.servlet.jsp.tagext,如果編譯有問題,可以去Tomcat的\common\lib檔案夾下面找jsp-api.jar引用上就可以了。
這個包裡面的類和介面,基本上我們主要關心的就是以“Tag”結尾的那幾個,介面Tag和BodyTag,類TagSupport和BodyTagSupport,還有一個介面IterationTag,不過一般不會用到。其他的我們都可以看作是輔助類,協助擷取資訊什麼的。我們可以仔細看看J2EE的API文檔裡面關於這個包的類說明。
上面類名裡面的Body的意思可能一下子比較難理解。tag指的就是像<tagname></tagname>這樣的東西,Body就是夾在tag中間的東西,比如<tagname>I am Body</tagname>。這麼一來,這個tag也就成了BodyTag,因為它可以帶Body。所以設計tag也要事先考慮好帶不帶Body,不過現實考慮,好像沒有Body的tag應該也比較少吧。
Tag介面是這些類裡面的根,所以先看看裡面有什麼。API文檔裡面那個Lifecycle圖畫的很粗糙,不過也能大致看清楚。我們也不過分糾纏細節,大致關心的就是doStartTag() 和doEndTag() 這一段。每當你寫的tag在Jsp頁面裡面要被解釋的時候,伺服器就自動調用你的類裡面的doStartTag()函數來完成你定義的邏輯,當解析完標籤後調用doEndTag()。實現Tag介面來定製自己的tag無疑是最靈活的。但是,難度也比較大,我們定義自己的tag的時候完全不必要搞得這麼有內涵。
BodyTag跟Tag類也差別不大,BodyTag繼承自Tag和IterationTag,因為涉及了Body的原因,邏輯要複雜一些。API文檔裡面的Lifecycle圖也比較清晰。有必要好好看看。裡面主要說明的就是函數調用的順序。但是在具體應用中,不一定都要按部就班的走完這整個Lifecycle,如果要想控制這些調用的路線。就要借用函數的傳回值了,在上一個函數返回特定的值(都是已經定義好的常數)就可以改變伺服器調用下一個函數的行為來完成你自己的邏輯。看到這裡我也不禁佩服這些寫類庫的人,能想出這麼個辦法來解決問題。
為了方便我們開發,又提供了兩個帶“Support”的類來“支援”我們,方便我們開發。一般情況下我們只要繼承這兩個類中的一個,而且我覺得BodyTagSupport也更常用一些好像。要說明的一點就是兩個Support類中TagSupport是BodyTagSupport的父類。類中的getId()和setId()這兩個函數名並不是死的,這兩個“Id”應該在你的程式中替換成你的標籤名,比如你的tag名字是tagname,就是<tagname>,那麼函數名就變成了getTagname ()和getTagname ()。這樣的搞法原來在其他地方也有領教。(注意tagname第一個字母在函數名中大寫)變化的名字有伺服器自己去處理,無需編程者自己操心。原來函數名都是可以變化的,一定要注意。
說到這裡可以結合Sun的文檔的代碼看看,就明白了。
至於部署和.tlb檔案的格式,Sun文檔上也都有。不再贅述。最後附上整理的傳回值列表,這個我認為比較重要。
英文Evaluate大致是“評估,求值”的意思,這裡我們可以理解為伺服器“讀取,讀入,處理”的意思,翻譯的時候我就隨語境變通一下,下面加了底線,如果有不當,請指正。
EVAL_BODY_INCLUDE:把Body讀入存在的輸出資料流中,doStartTag()函數可用
EVAL_PAGE:繼續處理頁面,doEndTag()函數可用
SKIP_BODY:忽略對Body的處理,doStartTag()和doAfterBody()函數可用
SKIP_PAGE:忽略對餘下頁面的處理,doEndTag()函數可用
EVAL_BODY_TAG:已經廢止,由EVAL_BODY_BUFFERED取代
EVAL_BODY_BUFFERED:申請緩衝區,由setBodyContent()函數得到的BodyContent對象來處理tag的body,如果類實現了BodyTag,那麼doStartTag()可用,否則非法
EVAL_BODY_AGAIN:請求繼續處理body,返回自doAfterBody(),這個傳回值在你製作迴圈tag的時候是很有用的。我觀察了一下JSTL的原始碼,想看看它的ForEach怎麼編製的,但是一看裡面邏輯異常複雜,短時間不能看出頭緒,所以在這裡也不敢妄言,如果哪位仁兄有研究,還請不吝賜教。
:包裡面的其他類還沒有研究,如果有研究再另行寫個文檔。