SimpleFramework系列之 - AjaxRequest
一、綜述
AjaxRequest是一個非常重要的組件,在一個基于SimpleFramework的項(xiàng)目中,AjaxRequest被使用的概率幾乎在50%以上,甚至更多。
在開始介紹AjaxRequest之前,我們首先看看HttpServletRequest,下圖介紹一個完整Http請求到響應(yīng)的生命周期。
一些Web框架(比如:Struts)擴(kuò)展了Servlet,并通過提供的接口,實(shí)現(xiàn)了基于MVC的編程模式,從而取代傳統(tǒng)的Servlet編程。如下圖:
隨著Ajax的流行,基于Ajax的請求變的越來越流行,一般要通過如下幾個步驟來實(shí)現(xiàn):
編寫客戶端代碼(javascript)
編寫請求代碼
通過回調(diào)函數(shù)處理返回的結(jié)果
編寫Servlet處理類
返回結(jié)果(可以是html、xml、text或json),等待客戶端回調(diào)函數(shù)的處理
一些流行的javascript框架,比如Prototype、jQuery等都提供了對Ajax的封裝,您可以很容易的編寫客戶端的請求代碼,這里以Prototype為例:
- new Ajax.Request("/test.action", {
- postBody: "p1=v1&p2=v2",
- encoding: "UTF-8",
- onComplete:function(req) {
- var txt = req.responseText;
- //do data
- }
- );
“/test.action”請求一個Servlet類,并通過業(yè)務(wù)處理,把需要的數(shù)據(jù)返回給前端回調(diào)函數(shù)onComplete。
看似簡單的流程,卻有很多問題需要關(guān)注:
實(shí)際的項(xiàng)目有上百個甚至更多Ajax請求,那么前端javascript的數(shù)量和Servlet的數(shù)量就會增長很快。當(dāng)javascript出現(xiàn)錯誤或更改javascript代碼都會相當(dāng)麻煩,至于Servlet,您可以通過Struts等技術(shù)替代
提交表單需要拼接參數(shù),有沒有更好的辦法?
返回?cái)?shù)據(jù)的解析。建議在Servlet中直接生成json格式
如果返回?cái)?shù)據(jù)包含javascript文件(腳本)、CSS文件等,如何動態(tài)添加到dom中,如果dom中已經(jīng)存在這些文件,那又該如何處理
需要對返回?cái)?shù)據(jù)進(jìn)行緩存,是否可以處理?
解決以上的問題,你需要付出太多的代價,不過,沒關(guān)系,SimpleFramework提供的AjaxRequest組件,讓您用聲明的方式,快速完成Ajax請求。
二、原理
三、實(shí)踐
現(xiàn)在就開始我們的AjaxRequest之旅吧!
3.1 組件的聲明
SimpleFramework使用xml文件來描述組件,您可以參考http://simpleframework.net/doc/d2/2.4.1.html獲取更為詳細(xì)的信息。
以下是聲明的代碼片段:
- <ajaxRequest name="ajaxTestAction" handleClass="net.simpleframework.demo.TestAction"
- handleMethod="testMethod">
- </ajaxRequest>
在組件聲明中,名稱是必須的,且不能和其它組件名稱重復(fù),因?yàn)镾impleFramework通過Filter發(fā)現(xiàn)如上的定義,就會自動為客戶端生成 一個$Actions[“ajaxTestAction”]的javascript對象。在客戶端,您就可以通過這個唯一的名稱獲取其javascript對 象的引用。
如果您不了解$Actions,可以通過http://simpleframework.net/doc/d2/2.4.2.html來了解更多內(nèi)容。
3.2 與HTML頁面元素的事件綁定
HTML頁面元素(比如button)如何綁定到AjaxRequest組件“ajaxTestAction”呢?SimpleFramework采用了最原始的方式,代碼如下:
- <input type="button" value="提交" onclick="$Actions[‘ajaxTestAction’]();" />
很簡單吧,SimpleFramework并沒有改變現(xiàn)有的編程習(xí)慣,沒有標(biāo)簽庫,僅僅是簡單的HTML和Javascript。
3.3 如何提交數(shù)據(jù)
Ajax可以通過Get或POST來提交數(shù)據(jù),但您必須自己拼接參數(shù)序列,這個非常麻煩。SimpleFramework提供了一個屬性formSelector,快速提交HTML里您關(guān)心的數(shù)據(jù)區(qū)域,參考以下代碼:
- <ajaxRequest name="ajaxTestAction" handleClass="net.simpleframework.demo.TestAction"
- handleMethod="testMethod" formSelector=".div1, .div2 select">
再看一下HTML表單的定義:
- <div class="div1">
- ... ...
- </div>
- <div class="div2">
- ... ...
- </div>
- <input type="button" value="提交" onclick="$Actions[‘ajaxTestAction’]();" />
關(guān)于selector,如果您了解Prototype、jQuery等javascript框架,那就一定非常熟悉。如果不了解,建議先在網(wǎng)上Google一下,先了解什么是CSS選擇器。
上述含義是提交類名為“div1”下的所有表單元素和類名為“div2”下的select元素,這是不是比定義一個form標(biāo)簽要簡單很多呢。
注:如果提交二進(jìn)制文件,需使用submit組件或swfUpload組件。
3.4 編寫HandleClass
AjaxRequest組件的HandleClass可以理解為Struts的Action,其接口的定義如下:
- package net.simpleframework.web.page.component.base.ajaxrequest;
- public interface IAjaxRequestHandle extends IComponentHandle {
- IForward ajaxProcess(ComponentParameter compParameter) throws Exception;
- }
如果沒有指定handleMethod,則ajaxProcess將會執(zhí)行,如果指定了handleMethod,則執(zhí)行名稱為handleMethod的方法,其方法結(jié)構(gòu)和ajaxProcess是一樣的。
建議您繼承AbstractAjaxRequestHandle而不是實(shí)現(xiàn)IAjaxRequestHandle,因?yàn)槌橄蟾割悤峁┮恍┯幸饬x的方法給您使用,對于任何其它組件,這一原則總是適用的。
3.5 IForward介紹
handleClass將會返回IForward接口,類似Struts的ActionForward,但有不同。IForward有三個具體的實(shí)現(xiàn):
TextForward,返回純文本
JsonForward,返回Json格式的文本,構(gòu)造時需傳遞Map、List、Array等類型
UrlForward,返回HTML,構(gòu)造時需傳遞url地址
大部分情況,JsonForward是一個更好的選擇。
3.6 編寫回調(diào)腳本
定義回調(diào)腳本,參考如下代碼:
- <ajaxRequest name="ajaxTestAction" handleClass="net.simpleframework.demo.TestAction"
- handleMethod="testMethod">
- <jsCompleteCallback>
- alert(json);
- alert(responseText);
- </jsCompleteCallback>
- </ajaxRequest>
3.6.1 回調(diào)函數(shù)原型
在編寫jsCompleteCallback的時候,很多用戶不知道如何下手,更不知道返回的數(shù)據(jù)在哪。其實(shí),jsCompleteCallback就是一個javascript函數(shù),只不過采用xml描述,把傳遞給你的參數(shù)省略了。請看jsCompleteCallback原型的定義:
- jsCompleteCallback = function(req, responseText, json) {
- }
解釋一下三個參數(shù):
req:原生ajax response對象
responseText:返回的文本對象
json:如果handleClass返回的是JsonForward,則json為解析過的JSON對象
3.6.2 通過屬性直接綁定到HTML區(qū)域
ajaxRequest很多應(yīng)用都是返回一段HTML,然后更新到某個區(qū)域,如果通過jsCompleteCallback一定會很簡單,下面是一段代碼樣例:
- var div = $("divid");
- div.innerHTML = responseText;
ajaxRequest同時還提供了一個屬性updateContainerId,可以不用寫jsCompleteCallback,而直接綁定到updateContainerId指定的區(qū)域id,不光如此,還能執(zhí)行responseText中的js函數(shù),代碼如下:
- <ajaxRequest name="ajaxTestAction" handleClass="net.simpleframework.demo.TestAction"
- handleMethod="testMethod" updateContainerId="divid">
- </ajaxRequest>
四、高級特性
4.1 動態(tài)傳遞參數(shù)
如果提交的數(shù)據(jù)是變化的,或則ajaxRequest組件是一個,但綁定的HTML元素事件是多個,又該怎么處理呢?
舉個實(shí)例,比如“發(fā)送郵件”,一般分為“保存到草稿”、“直接發(fā)送”,因?yàn)樘峤坏臄?shù)據(jù)是一樣的,則可以通過動態(tài)參數(shù)傳遞,在兩個按鈕的事件上分別綁定到同一個ajaxRequest組件。假設(shè)ajaxRequest組件的名稱為sentMail,參考如下代碼:
- <input type="button" value="保存到草稿" onclick="$Actions[‘sentMail’]('type=0');" />
- <input type="button" value="直接發(fā)送" onclick="$Actions[‘sentMail’]('type=1');" />
$Actions[‘sentMail’]其實(shí)就是一個函數(shù),你在調(diào)用的時候,可以設(shè)置參數(shù)為拼接的字符串(見代碼紅色部分),這是一個經(jīng)常使用的特性。還需要注意一點(diǎn),參數(shù)傳遞的優(yōu)先級是高于formSelector的。
4.2 自動加載js及css文件
自動加載js及css文件是ajaxRequest組件一個非常重要的特性,您可以直接在Ajax的返回?cái)?shù)據(jù)中定義js或css文件,而不必?fù)?dān)心它們是否已加載,如何加載等一系列問題。
您可以通過firebug來體驗(yàn)自動加載過程:)
4.3 作為其它組件的引用
組件的引用是SimpleFramework組件體系一個非常實(shí)用的功能。比如,window組件通過引用ajaxRequest組件來裝載window面板內(nèi)容,代碼如下:
- <ajaxRequest name="ajaxTestPage">
- <urlForward>/window_content.jsp</urlForward>
- </ajaxRequest>
- <window name="testWindow" contentRef="ajaxTestPage" width="480" height="600">
- </window>
當(dāng)調(diào)用了testWindow組件,ajaxTestPage將被觸發(fā)并返回/window_content.jsp生成的數(shù)據(jù)到window面板。以后還會對此特性做更多的介紹。
4.4 緩存返回的數(shù)據(jù)
ajaxRequest組件的緩存功能非常簡單,設(shè)置屬性updateContainerCache=true即可。如果您是注冊用戶,可以在SimpleFramework站點(diǎn)上體驗(yàn)一下:右上方的個人屬性編輯,采用的是標(biāo)簽頁,當(dāng)標(biāo)簽頁被打開后,下次將使用緩存功能。
4.5 一些不常用的屬性
disabledTriggerAction,當(dāng)組件被調(diào)用時,是否禁止調(diào)用元素,默認(rèn)為true,目的是防止被多次調(diào)用,比如用戶連續(xù)的點(diǎn)擊操作
parallel,是否允許并行執(zhí)行,默認(rèn)為false,在連續(xù)調(diào)用ajaxRequest時,在允許并行時,才可同時執(zhí)行,否則將拋棄當(dāng)前的調(diào)用
jobExecute,執(zhí)行權(quán)限,該屬性依賴機(jī)構(gòu)模塊
confirmMessage,客戶端需要確認(rèn)的消息
throwException(window、alert),異常的展示方式。提供alert展示或window組件展示,window組件展示可獲取更多的異常信息
showLoading,是否顯示裝載進(jìn)度(右上角顯示),默認(rèn)為true