在JSP開發中模擬.NETWebForm(二)
|
WebForm這樣的機制使得web開發如此地接近于桌面應用的開發,使開發變得更簡單。而且我相信,asp.net這樣作并沒有什么性能上的損失,我們可以將asp.net生成的webForm的cs源文件和Jsp容器生成的jsp文件的java源文件,不難得到這一結論。
可惜,如果我們在現有Jsp容器規范的約束下實現我們的想法,則不免要損失一些性能。前面我們在實現PageHandler的事件機制時,已經運用了java的反射機制,下面要實現服務器端控件,恐怕不免又要作一些額外的工作。
觀察由tomcat生成的帶有tag的jsp頁面的java源文件,會發現每一個tag都會根據其在jsp文件中出現的位置而在java源文件中的對應位置被實例化(resin生成的源碼還與tomcat不一樣,tomcat會對每一個出現的標簽實例化,而resin則對同類的tag只實例化一次),猶如如下的格式:
| ButtonTag _button1 = new ButtonTag(); _button1.setPageContext(pageContext); _button1.setParent(null); _button1.setCaption("我的按鈕"); _button1.setId("button1"); _button1.setOnclick("clickme()"); try { int ret=_button1.doStartTag(); if (ret!=Tag.SKIP_BODY) { try { if (ret!=Tag.EVAL_BODY_INCLUDE) { out = pageContext.pushBody(); _button1.setBodyContent((BodyContent) out); _button1.doInitBody(); } do { ...處理tag的body }while(_button1.doAfterBody()==BodyTag.EVAL_BODY_AGAIN) } finally { if (ret!=Tag.EVAL_BODY_INCLUDE) { out = pageContext.popBody(); } } } if (_button1.doEndTag()==Tag.SKIP_PAGE) return; } finally { _button1.release(); } |
當然,隨著tag是BodyTagSupport還是TagSupport,生成的代碼會有些不同。
假設以上調用頁面上所有tag的代碼稱為A,則我們希望最終生成的代碼有類似如下的結構:
1:PageHandler handler=new MyPageHandler();
2:handler.prepareProcess(pageContext);//作處理前的初始化工作
3:handler.onInit();
4:A;//在A 執行過程中,我們希望能將tag的實例按順
//序添加到PageHandler的一個集合中
5:handler.onLoad();//此時,所有控件已經初始化完畢
6:handler.onEvent();//如果有請求的事件,則處理
7:handler.render();//向頁面輸出html代碼,pageHandler會調用每個控件
//的寫出html的方法,同時,摧毀每個控件
8:handler.onUnload();
在以上步驟中,1、2、6、7由PageHandler基類完成,6會自動調用MyPageHandler的適當方法。4由PageHandler和各個tag協同完成,主要是按照tag的出現順序將其添加入MyPageHandler中,甚至能同MyPageHandler中聲明的同名控件對象引用向聯系。3、6、8由MyPageHandler負責重寫,MyPageHandler還要負責事件處理的邏輯實現。
這樣,在第四步以后,MyPageHandler都可訪問到頁面中的tag實例,并可在4、5步驟中控制這些tag,在7中,tag會依據其自身最新的狀態向客戶端寫出html文本。
現在,在第4步還存在困擾我們的問題。