1、建立dwr.xml 配置文件
任何一個dwr.xml的文件都需要包含DWR DOCTYPE的聲明行,格式如下:




整個配置文件的大體結(jié)構(gòu)如下:









































有幾個術(shù)語有必要理解: 參數(shù)叫做converted,遠(yuǎn)程Bean叫做created.如果遠(yuǎn)程Bean A有個方法A.blah(B),那么你需要為A建立一個created,為B建立一個converted.
配置文件init部分聲明那些用于建立遠(yuǎn)程bean和在方法調(diào)用中轉(zhuǎn)換bean的類.這部分是可選擇性配置的,多數(shù)情況下可以不必使用它,如果你想定義一個新的creator或者converter那么就必須在部分中聲明,but do double check on the ones that are currently available first.
在init部分的作用是告訴DWR一些類實例和關(guān)于這些類怎樣運行的信息.實際上并不會使用.這有點向java中的import語句,多數(shù)類在使用之前需要引入,但引入了類并不意味著這些在使用,每個creator和converter需要有個id屬性來允許以后進(jìn)行引用.
配置文件的allow部分定義哪些類可以建立和轉(zhuǎn)換,每個被準(zhǔn)許的類都可以有一個'create'或者'convert'配置行.下面列出的類的轉(zhuǎn)換在默認(rèn)情況下不需要進(jìn)一步的設(shè)置.
1、所有基本類型,boolean,int,double等等
2、基本類型的對象形式實現(xiàn)的類,Boolean,Integer等等
3、java.lang.String
4、java.util.date 和三個SQL形式的派生類
5、以上所有類型的數(shù)組形式
6、以上所有類型的集合,List,Set,Map(有些局限性)
However nothing is added to the list of classes that can be created (i.e. put up for remoting) without you declaring it.
2、The Converters
DWR已經(jīng)默認(rèn)定義和初始化了常用的Converter,他們分別如下:


























































這里僅僅是定義了Converter并且簡單的放在<convert….>元素之內(nèi),任何的<convert….>元素內(nèi)容都有兩個必須定義的屬性.一個是對converter定義的引用和converter能夠轉(zhuǎn)換的類.
例如最簡單的converter是null converter,它作用是把null和void值轉(zhuǎn)換成javascript的null和undefined值.它是所有converter中最簡單的,就象調(diào)用java的靜態(tài)方法一樣,所以并不需要創(chuàng)建對象.
默認(rèn)的時候DWR將java void值轉(zhuǎn)換成javascript的null值就是這樣設(shè)置de><convert converter="null" match="void"/>de>. 有時java.lang.Void也需要進(jìn)行這樣的轉(zhuǎn)換,所以設(shè)置也是相似的<convert converter="null" match="java.lang.Void"/>.從java中傳遞null值到j(luò)avascript是沒有任何危險性的,所以DWR將這個作為默認(rèn)的converter,所以你自己不用再把這個converter添加到配置文件的<allow>部分中去.
基本類型的converter轉(zhuǎn)換int,boolean,double等.當(dāng)然還包括對應(yīng)的對象形式Integerv,Boolean等等.DWR中在allow預(yù)定義了16個配置項目分別用于所有基本類型的轉(zhuǎn)換.就象這樣<convert converter="primitive" match="java.lang.Long"/><convert converter="primitive" match="long"/>.
String類型和Date同樣預(yù)先定義了Converter,這些converter都沒有辦法進(jìn)行改變的,所有的String,Date和數(shù)值類型都統(tǒng)一采用默認(rèn)的converter.
2.1 Array Converters
Array的配置項目沒有上面介紹的那么直觀,默認(rèn)情況下DWR裝載所有的基本類型和可裝載的對象,這些包括String,Date等先前介紹的類型.java高級程序員可能會理解為什么match的這行有點奇怪.


















*符號在上面沒有提到,其實這是個可以表示任何字符的通配符號.這些數(shù)組可裝載的的類型和其他可裝載的類型是一樣的.
2.2 Bean Converters
一種不能采用默認(rèn)方式定義的converter就是Bean Converter,這個是將POJO對象轉(zhuǎn)換成javascript相關(guān)的數(shù)組,反向也一樣.基于安全因素的考慮這種類型的converter不能采用默認(rèn)的方式實現(xiàn).
假設(shè)有個bean并且通過<create ...>語句設(shè)置成遠(yuǎn)程可用,有種類型的參數(shù)他本身是一個帶有setter的java bean,但setter會產(chǎn)生嚴(yán)重的隱患.攻擊者可能促使這隱患的發(fā)生.通過下面的語句就可以設(shè)置但個類的bean converter

要想允許轉(zhuǎn)換指定包或子包下所有類的轉(zhuǎn)換可以按照下面的設(shè)置

很明顯,可以采用下面的方式來轉(zhuǎn)換所有的java bean

2.3 Restricting Property Conversion(指定屬性轉(zhuǎn)換)
將象用exclude和incluce來通知DWR隔離creator的方法一樣,converter也有一個類似的配置方法.因為指定屬性轉(zhuǎn)換只有針對bean才有效(基本類型的轉(zhuǎn)換沒有必要指定屬性),這個功能只能應(yīng)用與特定的converter即BeanConverter和從次類派生的所有類.相關(guān)配置語法如下






這樣就可以限定DWR不能調(diào)用Fred對象的getProperty1()和getProperty2()方法,通常這被成為拒絕訪問方式,當(dāng)然你也可以采用下面的方式配置可以訪問的方法(授權(quán)訪問方式)






較好的安全控制大部分都是采用授權(quán)訪問方式.
2.4 Collection Converters
DWR最后兩個默認(rèn)的converter是Maps和Collections




通常converter是采用遞歸方法轉(zhuǎn)換集合中的所有對象.
這里有兩個地方需要注意:
僅僅通過反射方法沒有辦法知道集合元素中的類型,所以上面的兩個converter能將任何集合轉(zhuǎn)換成相對javascript而言有意義的對象.然而沒有辦法將不同的集合類類型分別采用不同的轉(zhuǎn)換方法.因為沒有辦法完全自動進(jìn)行轉(zhuǎn)換,我們可以應(yīng)用dwr.xml文件的special signatures syntax配置部分設(shè)置類型的轉(zhuǎn)換處理過程.
2.5 DOM Objects
DWR 自動將DOM、DOM4J、JDOM和XOM轉(zhuǎn)換成DOM樹,前面這幾種類型都僅僅返回Document,Element,Node.DWR會自動將這些轉(zhuǎn)換成瀏覽器DOM對象.通常在啟動JDOM Converter時會有一個提示信息,除非你想采用JDOMconverter否則可以忽略.
INFO: Missing classdef for converter 'jdom'. Failed to load uk.ltd.getahead.dwr.convert.JDOMConverter. Cause: org/jdom/Document
因為DWR沒有辦法知道你是否采用jdom converter,所以提示信息是info級別.如果你想采用jdom converter,你必須很清楚地知道jdom converter是否可以被加載.這就是DWR保留上面的提示信息的原因.
3 The Creators
DWR共有三種Creator,最簡單的”new”是調(diào)用bean的默認(rèn)構(gòu)造函數(shù)創(chuàng)建實例.”scripted”允許采用其他腳本語言創(chuàng)建實例.如BeanShell.在遠(yuǎn)程bean的默認(rèn)構(gòu)造函數(shù)不能進(jìn)行進(jìn)一步配置的情況下這種類型的creator比較有用.”Spring”類型允許你通過spring創(chuàng)建實例.
下面是關(guān)于creator的參考資料和配置參數(shù)說明.
Creator
Parameter
User
new
class
類的全名稱(包括包路徑)
scripted
language
BSF框架支持的腳本語言名稱(BSF為apache項目)
scripted
script
返回遠(yuǎn)程對象的腳本,腳本可以指定一些屬性,多數(shù)情況下一般只設(shè)置param節(jié)點配置.屬性很少設(shè)置.
spring
Location*
任何以location開頭的參數(shù),每個參數(shù)都是指定一個spring的配置文件,在參數(shù)沒有設(shè)置的情況下DWR會去讀取spring的全局的配置文件.
spring
beanName
從配置文件中讀取的bean的名稱
“scope參數(shù)允許你配置creator的生命周期,共有以下幾個選項:application,session,request,page.這些參數(shù)對于用過jsp或servlet的開發(fā)人員并不陌生.
3.1 Uing static methods
如果你想遠(yuǎn)程調(diào)用一個creator的靜態(tài)方法,并且creator是new類型.因為調(diào)用遠(yuǎn)程bean的方法前DWR不會檢測將要執(zhí)行的方法是不是靜態(tài)方法,如果是靜態(tài)方法那么creator就不用創(chuàng)建.這種機制可以適用任何類型的creator,但new類型的creator是最簡單配置的.
3.2 Security
Creator可以配置類的成員函數(shù)的訪問權(quán)限.creator有授權(quán)訪問(指明可以被訪問的方法)和拒絕訪問(指明不允許訪問的方法)兩種配置方式.
如果要設(shè)置除了setWibble方法之外的所有方法都不可訪問可以采用下面的設(shè)置.








如果采用j2ee訪問角色控制的模式








3.3 The 'spring' Creator
3.4 The 'new' Creator
DWR已經(jīng)默認(rèn)定義了new creator.

DWR已經(jīng)將這配置到了內(nèi)置的dwr.xml文件中,并不需要進(jìn)行額外的配置.
Creator通過調(diào)用類的默認(rèn)的構(gòu)造方法創(chuàng)建實例.應(yīng)用new creator有以下幾個優(yōu)點:
? 安全性
生命周期比較短的creator可以得到更好的安全性,通過不同的應(yīng)用情況設(shè)置適合的生命周期.
? 低內(nèi)存開銷
在訪問量比較大的情況下,可以不用擔(dān)心發(fā)生內(nèi)存泄露的情況.
配置一個creator的創(chuàng)建和遠(yuǎn)程方法調(diào)用設(shè)置:













上面的配置信息表示將java.util.date提供給客戶端調(diào)用,并且引用名稱是Blash.當(dāng)你在客戶端調(diào)用Blash.toString(reply)時,后臺將采用java.util.date的默認(rèn)構(gòu)造方法創(chuàng)建一個實例.然后調(diào)用實例的tostring方法.客戶端的javascript將返回給reply對象(此時reply是java.util.date的字符串形式)
3.5 The 'scripted' Creator
DWR 已經(jīng)默認(rèn)配置了scripted creator配置,

這種類型的creator采用BSF執(zhí)行腳本語言并返回bean.例如
























4 Signatures in dwr.xml
Signatures部分用于配置Collections中裝載對象元素的類型.舉個例子來說:下面的java代碼沒有辦法對List集合中的對象進(jìn)行轉(zhuǎn)換.















Singatures配置允許我們對DWR要操作的對象類型進(jìn)行配置.對于了解JDK5泛型編程的開發(fā)人員來說下面的格式是很容易理解的.
<signatures>
<![CDATA[
import java.util.List;
import com.example.Check;
Check.setLotteryResults(List<Integer> nos);
]]>
</signatures>
DWR有個專門用于解析上面配置語句的解析器,雖然上面的是JDK5中才有的特性,因為有解析器的原因這也可以應(yīng)用與JDK5之前的版本.
解析規(guī)則是不可見的,但有兩種例外情況.
一種情況是因為DWR1.0的解析器中有個Bug,在有些場合會無法處理返回值的類型.所以應(yīng)該要避免這種情況的發(fā)生.
一種情況是因為解析器是一個語法寬松的解析器,他不象編譯器一樣對語法有非常嚴(yán)格的要求,所有有時可能一些重要的語句沒有配置而無法事先發(fā)現(xiàn).












DWR的將來版本可能會采用符合java官方規(guī)范的解析器,這樣可以避免許多出錯的情況.
Signature部分只用于泛型參數(shù)到基本類型參數(shù)的轉(zhuǎn)換,對于其他的類型DWR采用反射機制或運行時類型來確定.在沒有泛型參數(shù)的情況下可以不配置Signature.
public void method(String p);
public void method(String[] p);
下面的就需要配置,因為反射機制無法完成次類功能.
public void method(List<Date> p);
public void method(Map<String, WibbleBean> p);
下面可以不用配置,DWR可以自動完成轉(zhuǎn)換.
public void method(List<String> p);
public void method(Map<String, String> p);
下面可以不用設(shè)置,DWR可以采用運行時轉(zhuǎn)換.
public List<Date> method(String p);
有一個值得注意的地方是在javascript中所有對象的keys都是一個字符串,你也可以把其他對象作為keys.他們在使用之前都會轉(zhuǎn)換成字符串形式.DWR1.x將采用這個特性來轉(zhuǎn)換成String.以后對象的轉(zhuǎn)換將會在服務(wù)器端完成.
5 Scripting Introduction
DWR生成的javascript代碼和java代碼很相似并通過dwr.xml配置輸出.相比普通java異步調(diào)用之下,通過ajax生成遠(yuǎn)程接口和java 代碼的最大挑戰(zhàn)是AJAX異步功能.
DWR通過引入一個回調(diào)函數(shù),當(dāng)數(shù)據(jù)從服務(wù)返回數(shù)據(jù)是調(diào)用這個函數(shù)。有兩種推薦的方法使用回調(diào)函數(shù)。一在參數(shù)列表加入回調(diào)功能。二增加調(diào)用元數(shù)據(jù)對象調(diào)用。
也可以將回調(diào)的功能放在參數(shù)列表的前頭,但是不建議使用這樣的用法,因為在處理自動HTTP對象時候會出現(xiàn)問題。這些方法一般會保持向后兼容。
5.1 Simple Callback Functions
假設(shè)有個下面的java方法。
public class Remote
{
public String getData(int index) { ... }
}
在javascript中就可以以下面的方式引用。













{







“42”只是一個傳給getdata方法的參數(shù)。當(dāng)然你可以采用下面的寫法。
Remote.getData(42, function(str) { alert(str); });
5.2 Call Meta-Data Objects
另一種使用回調(diào)功能的方法是指定一個回調(diào)功能選項或其他可選項。上面的例子就變成下面的形式。
Remote.getData(42, {
callback:function(str) { alert(str); }
});
這個方法具有以下幾個優(yōu)點:可以依照你的編碼習(xí)慣來編寫程序,更重要的是允許你增加額外的調(diào)用選項。
5.3 Timeouts and Handling Errors
除了使用回調(diào)功能你還可以指定超時時限和錯誤處理方法。例如:
Remote.getData(42, {
callback:function(str) { alert(str); },
timout:5000,
errorHandler:function(message) { alert("Oops: " + message); }
});
5.4 Finding the callback method
下面有幾個實例來說明回調(diào)功能各個參數(shù)選項的配置,因為javascript是不支持函數(shù)重載的。
Remote.method({ timeout:3 }, { errorHandler:somefunc });
上面的兩個參數(shù)一個是bean的參數(shù)一個是回調(diào)元數(shù)據(jù)對象。但是沒有方法去區(qū)別這兩種參數(shù)選項。在拋開特定的瀏覽器環(huán)境,我們假設(shè)null==undefined,所以具有以下規(guī)則:
一、如果一個函數(shù)的每個調(diào)用都是回調(diào)函數(shù),那么他就沒有調(diào)用元數(shù)據(jù)對象,所有的參數(shù)都是普通java參數(shù)。
二、如果一個最后一個參數(shù)具有一個回調(diào)功能,那么這個參數(shù)就是調(diào)用元數(shù)據(jù)對象。其余的就是普通java參數(shù)。
三、如果第一個參數(shù)為null,我們就認(rèn)為沒有回調(diào)功能。其余的就是普通java參數(shù)。此外還要檢查最后一個參數(shù)是否為null,如果是則會給予提示信息。
四、如果最后一個參數(shù)為null,則沒有回調(diào)功能。
五、還有一個不是很好的約定格式,要表示錯誤信息。
6 Engin.js文件
這個文件是DWR的引擎文件,他承擔(dān)著把后臺自動生成的javascript接口與前臺調(diào)用之間的銜接責(zé)任。所以任何使用DWR的地方都需要這個文件。
每個使用DWR的頁面都必須引入這個文件:
<script type='text/javascript'
src='/[YOUR-WEB-APP]/dwr/engine.js'>
</script>
6.1 Call Batching
應(yīng)用批量功能可以一次性調(diào)用多個遠(yuǎn)程bean方法,因為他是將多個調(diào)用做為一次請求,這就減少了與服務(wù)器的交互。可以減少許多的開銷。
一個批量方法調(diào)用以DWREngine.beginBatch()開始WREngine.endBatch()結(jié)束。當(dāng)DWREngine.endBatch()被調(diào)用時就說明開始調(diào)用批量方法,DWR就將這些方法打包在一起作為一次請求發(fā)送給服務(wù)器。
DWR會確保所有的方法都回被調(diào)用,所以使用批量功能是要注意是否提交了批量調(diào)用,如果沒有提交批量調(diào)用那么這些需要調(diào)用的方法將永遠(yuǎn)排在調(diào)用隊列中直到提交批量調(diào)用。
注意:批量調(diào)用方法會有一些缺點,比如他不能在那些已經(jīng)幫定在一起的方法調(diào)用順序不能保證同步。
例如所有的調(diào)用元數(shù)據(jù)對象的接管函數(shù),超時設(shè)定,錯誤處理等的調(diào)用都是在批量的級別上,而不是在調(diào)用的級別上。如果一個批量調(diào)用含有兩個不同超時時間設(shè)定的方法,那么除了最后一個之外的所有其他方法的超時設(shè)定都被忽略。
6.2 Call Ordering
因為AJAX是個普通的異步遠(yuǎn)程方法調(diào)用模式,所以遠(yuǎn)程調(diào)用的返回結(jié)果的順序可能和你發(fā)送請求的順序不一致。DWREngine.setOrdered(boolean)方法允許你設(shè)置遠(yuǎn)程調(diào)用返回結(jié)果的順序和你發(fā)送調(diào)用請求的順序保持一致。DWR是通過一個遠(yuǎn)程方法調(diào)用已經(jīng)結(jié)束后在發(fā)送下一個調(diào)用請求來實現(xiàn)這個功能的。
一般情況我們并不需要返回結(jié)果順序和發(fā)送請求順序保持一致。DWR默認(rèn)是不保持一致的。
提示:因為保持上面的順序會對應(yīng)用程序的性能和響應(yīng)時間,如果其中的一個消息發(fā)生丟失那么瀏覽器可能會有意想不到以外情況發(fā)生。在使用這個功能的時候必須認(rèn)真考慮是否真的有必要使用。通常比較好的方法是使用異步模式調(diào)用。
6.3 Handling Errors and Warnings
對于一些服務(wù)器端發(fā)生的錯誤或警告情況DWR都回調(diào)用默認(rèn)的錯誤和警告方法并且傳遞一個相關(guān)信息,通常這些發(fā)生的錯誤和異常對于用戶來說是不可見的。
下面這個方法主要用于以消息框的方式或者在狀態(tài)欄里顯示一個錯誤或警告的消息。
要改變錯誤的處理方法可以使用這個方法:DWREngine.setErrorHandler(function),
改變警告的處理方法可以使用這個方法:DWREngine.setWarningHandler(function).
6.4 Remoting Hooks
參考 DWREngine.setPreHook(function) and DWREngine.setPostHook(function).
如果你想在執(zhí)行遠(yuǎn)程方法調(diào)用之前或之后進(jìn)行一些處理的話,你可以使用上面的兩個方法。上面參數(shù)中設(shè)置的目標(biāo)方法必須是沒有參數(shù)的。如果你想限制特定的組件在一次方法調(diào)用沒有結(jié)束之前不允許再次調(diào)用,那么使用上面的方法將很有用。
Post 執(zhí)行Hooks通常是設(shè)置pre-hooks,一般用來撤消先前的操作。關(guān)于Hooks的例子可以參照;DWRUtil.useLoadingMessage() 函數(shù)。
6.5 Remoting Options(遠(yuǎn)程調(diào)用設(shè)置)
關(guān)于DWR處理遠(yuǎn)程調(diào)用有若干個設(shè)置選項,Method和Verbs對于用戶來說是透明的,但對于不同的瀏覽器可能會有影響。通常DWR會選擇正確的方法處理,如果想饒過某些瀏覽器產(chǎn)生的影響這些參數(shù)設(shè)置將非常有用。
DWREngine.setMethod(newmethod)
設(shè)置Method的實際執(zhí)行方法,但被設(shè)置的方法不能確保被調(diào)用。只是DWR首先會嘗試調(diào)用這個方法。newmethod 必須是DWREngine.XMLHttpRequest 或著 DWREngine.IFrame.
DWREngine.setVerb(verb)
允許設(shè)置iframe 和 XMLHttpRequest提交數(shù)據(jù)時的方式,必須是POST或者GET,如果瀏覽器不支持POST形式,DWR會自動切換到GET方式。