????<servlet>
????????<servlet-name>dwr-invoker</servlet-name>
????????<display-name>DWR Servlet</display-name>
????????<description>Direct Web Remoter Servlet</description>
????????<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
????????<init-param>
????????????<param-name>debug</param-name>
????????????<param-value>true</param-value>
????????</init-param>
????</servlet>
????<servlet-mapping>
????????<servlet-name>dwr-invoker</servlet-name>
????????<url-pattern>/dwr/*</url-pattern>
????</servlet-mapping>
一個(gè)可選的步驟是設(shè)置DWR為調(diào)試模式—象上面的例子那樣—在servlet描述段中將debug參數(shù)設(shè)為true。當(dāng)DWR在調(diào)試模式時(shí),你可以從HTMl網(wǎng)頁中看到所有的可訪問的Java對(duì)象。包含了可用對(duì)象列表的網(wǎng)頁會(huì)出現(xiàn)在/WEBAPP/dwr這個(gè)url上,它顯示了對(duì)象的公共方法。所列方法可以從頁面中調(diào)用,允許你,第一次,運(yùn)行服務(wù)器上的對(duì)象的方法。下圖顯示了調(diào)試頁的樣子:

調(diào)試頁
現(xiàn)在你必須讓DWR知道通過XMLHttpRequest對(duì)象,什么對(duì)象將會(huì)接收請(qǐng)求。這個(gè)任務(wù)由叫做dwr.xml的配置文件來完成。在配置文件中,定義了DWR允許你從網(wǎng)頁中調(diào)用的對(duì)象。從設(shè)計(jì)上講,DWR允許訪問所有公布類的公共方法,但在我們的例子中,我們只允許訪問幾個(gè)方法。下面是我們示例的配置文件:
<dwr>
????<allow>
????????<convert converter="bean" match="dwr.sample.Apartment"/>
????????<create creator="new" javascript="ApartmentDAO" class="dwr.sample.ApartmentDAO">
????????????<include method="findApartments"/>
????????????<include method="countApartments"/>
????????</create>
????</allow>
</dwr>
上面的文件實(shí)現(xiàn)了我們例子中的兩個(gè)目標(biāo)。首先,<convert>標(biāo)記告訴DWR將dwr.sample.Apartment對(duì)象的類型轉(zhuǎn)換為聯(lián)合數(shù)組,因?yàn)椋鲇诎踩脑颍珼WR默認(rèn)的不會(huì)轉(zhuǎn)換普通bean。第二,<create>標(biāo)記讓DWR暴露出dwr.sample.ApartmentDAO類給JavaScript調(diào)用;我們?cè)陧撁嬷惺褂肑avaScript文件被javascript屬性定義。我們必須注意<include>標(biāo)記,它指明了dwr.sample.ApartmentDAO類的哪些方法可用。
HTML/JSP代碼
配置完成后,你就可以啟動(dòng)你的Web應(yīng)用了,這時(shí)DWR會(huì)為從你的HTML或Java服務(wù)器端頁面(JSP)上調(diào)用所需方法作好準(zhǔn)備,并不需要你創(chuàng)建JavaScript文件。在search.jsp文件中, 我們必須增加由DWR提供的JavaScript接口,還有DWR引擎,加入以下三行到我們的代碼中:
??<script src='dwr/interface/ApartmentDAO.js'></script>
??<script src='dwr/engine.js'></script>
??<script src='dwr/util.js'></script>
我們注意到當(dāng)用戶改變搜索標(biāo)準(zhǔn)時(shí),這是AJAX在示例程序中的首次應(yīng)用;正如他所看到的,當(dāng)標(biāo)準(zhǔn)改變時(shí),可用的公寓數(shù)量被更新了。我創(chuàng)建了兩個(gè)JavaScript函數(shù):當(dāng)某一個(gè)選擇下拉框中的值變化時(shí)被調(diào)用。ApartmentDAO.countApartments()函數(shù)是最重要的部分。最有趣的是第一個(gè)參數(shù), loadTotal()函數(shù),它指明了當(dāng)接收到服務(wù)端的返回時(shí)DWR將會(huì)調(diào)用的JavaScript方法。loadTotal于是被調(diào)用來在HTML頁面的<div>中顯示結(jié)果。下面是在這個(gè)交互場(chǎng)景中所使用到的JavaScript函數(shù):
function updateTotal() {
????$("resultTable").style.display = 'none';
????var bedrooms = document.getElementById("bedrooms").value;
????var bathrooms = document.getElementById("bathrooms").value;
????var price = document.getElementById("price").value;
????ApartmentDAO.countApartments(loadTotal, bedrooms, bathrooms, price);
}
function loadTotal(data) {
????document.getElementById("totalRecords").innerHTML = data;
}
很明顯,用戶想看到符合他的搜索條件的公寓列表。那么,當(dāng)用戶對(duì)他的搜索標(biāo)準(zhǔn)感到滿意,并且總數(shù)也是有效的話,他會(huì)按下顯示結(jié)果的按紐,這將會(huì)調(diào)用updateResults() JavaScript方法:
function updateResults() {
????
????DWRUtil.removeAllRows("apartmentsbody");
????var bedrooms = document.getElementById("bedrooms").value;
????var bathrooms = document.getElementById("bathrooms").value;
????var price = document.getElementById("price").value;
????ApartmentDAO.findApartments(fillTable, bedrooms, bathrooms, price);
????$("resultTable").style.display = '';
}
function fillTable(apartment) {
????DWRUtil.addRows("apartmentsbody", apartment, [ getId, getAddress, getBedrooms, getBathrooms, getPrice ]);
}
updateResults()方法清空了存放搜索返回結(jié)果的表域,從用戶界面上獲取所需參數(shù),并且將這些參數(shù)傳給DWR創(chuàng)建的ApartmentDAO對(duì)象。然后數(shù)據(jù)庫(kù)查詢將被執(zhí)行,fillTable()將會(huì)被調(diào)用,它解析了DWR返回的對(duì)象(apartment),然后將其顯示到頁面中(apartmentsbody)。
安全因素
為了保持示例的簡(jiǎn)要,ApartmentDAO類盡可能的保持簡(jiǎn)單,但這樣的一個(gè)類通常有一組設(shè)置方法來操作數(shù)據(jù),如insert(), update()和delete()。DWR暴露了所有公共方法給所有的HTML頁面調(diào)用。出于安全的原因,像這樣暴露你的數(shù)據(jù)訪問層是不明智的。開發(fā)者可以創(chuàng)建一個(gè)門面來集中所有JavaScript函數(shù)與底層業(yè)務(wù)組件之間的通信,這樣就限制了過多暴露的功能。
結(jié)論
這篇文章僅僅讓你在你的項(xiàng)目中使用由DWR支持的AJAX開了個(gè)頭。DWR讓你集中注意力在如何提高你的應(yīng)用的交互模型上面,消除了編寫和調(diào)試JavaScript代碼的負(fù)擔(dān)。使用AJAX最有趣的挑戰(zhàn)是定義在哪里和如何提高可用性。DWR負(fù)責(zé)了操作Web頁面與你的Java對(duì)象之間的通信,這樣就幫助你完全集中注意力在如何讓你的應(yīng)用的用戶界面更加友好,
我想感謝Mircea Oancea和Marcos Pereira,他們閱讀了這篇文章并給予了非常有價(jià)值的返匱。
資源
·javaworld.com:
javaworld.com
·Matrix-Java開發(fā)者社區(qū):
http://www.matrix.org.cn/
·onjava.com:
onjava.com
·下載示例程序的全部源碼:
http://www.javaworld.com/javaworld/jw-06-2005/dwr/jw-0620-dwr.war
·DWR: http://www.getahead.ltd.uk/dwr/index.html
·HSQL:http://hsqldb.sourceforge.net/
·AJAX的定義:http://en.wikipedia.org/wiki/AJAX
· “AJAX:通向Web應(yīng)用的新途徑": Jesse James Garrett (Adaptive Path, 2005.2): http://www.adaptivepath.com/publications/essays/archives/000385.php
· “非常動(dòng)態(tài)的Web界面” Drew McLellan (xml.com, 2005.2): http://www.xml.com/pub/a/2005/02/09/xml-http-request.html
·XMLHttpRequest & AJAX 工作范例: http://www.fiftyfoureleven.com/resources/programming/xmlhttprequest/examples
· “可用的XMLHttpRequest實(shí)踐” Thomas Baekdal (Baekdal.com, 2005.3): http://www.baekdal.com/articles/Usability/usable-XMLHttpRequest/
·"XMLHttpRequest使用導(dǎo)引" Thomas Baekdal (Baekdal.com,??2005.2):http://www.baekdal.com/articles/Usability/XMLHttpRequest-guidelines/
·AJAX實(shí)質(zhì):http://www.ajaxmatters.com/
(看完后個(gè)人感覺:有了DWR就JAVA開發(fā)而言,完全可以與AJAX匹敵啦,省了在JS上對(duì)XMLHTTP以及對(duì)DOM的處理,不可以避免地在后臺(tái)對(duì)應(yīng)的IO處理;然后就DWR來說,它增加了對(duì)XML中對(duì)應(yīng)的配置--在開源框架中似乎一直不曾停止過。還有對(duì)一些DWR自有用法如DWRUtil.addRows得參考其相關(guān)文檔---當(dāng)然這樣的功能我們自己也可以用JS來解決,并且它顯然很實(shí)用。)
DWRUtil學(xué)習(xí)
這些功能函數(shù)在下面這個(gè)網(wǎng)址都有示例,這里只是把他們用中文解釋,方便查找.
http://getahead.ltd.uk/dwr/browser/utilDWRUtil.getText(id)
這個(gè)函數(shù)只能用于select
getText(id) is similar to getValue(id), except that it is designed for <select ... lists where you need to get the displayed text rather than the value of the current option.
這個(gè)函數(shù)主要的作用是取到當(dāng)前select的顯示值即<option value>xxx</option>中xxx的內(nèi)容
DWRUtil.getValue(id) 用來得到<option value>xxx</option>等元素的value值
DWRUtil.getValue(id) is the read version of setValue(). This gets the values out of the HTML elements without you needing to worry about how a selection list differs from a div.
這個(gè)函數(shù)能用于多個(gè)元素input type =textarea,text,Form button,formbutton,password(明文),
Fancy button等元素,主要可以屏蔽原來對(duì)select元素getValue操作帶來的不便
DWRUtil.getValues()
getValues() is similar to getValue() except that the input is a Javascript object that contains name/value pairs. The names are assumed to be the IDs of HTML elements, and the values are altered to reflect the contents of those IDs. This method does not return the object in question, it alters the value that you pass to it.
此函數(shù)主要是一次完成多個(gè)元素的getValue()操作,并將value的結(jié)果以js對(duì)象的形式封裝起來返回,參數(shù)是一個(gè)js對(duì)象,其中包含了希望取到value的element id
e.g
{ div:null, textarea:null, select:null, text:null, password:null, formbutton:null, button:null}
詳細(xì)參考
http://getahead.ltd.uk/dwr/browser/util/getvalues查看效果
DWRUtil.onReturn
When inputs are part of a form then the return key causes the form to be submitted. When you are using Ajax, this is generally not what you want. Usually it would be far better if some JavaScript was triggered.Unfortunately different browsers handle events in quite a different manner. So DWRUtil.onReturn patches over the differences.
在一個(gè)form表單中敲回車鍵將導(dǎo)致表單被遞交,這往往不是我們希望看到的.但是很多瀏覽器對(duì)這個(gè)事件的處理是不統(tǒng)一的,這個(gè)函數(shù)就是為了消除這個(gè)不統(tǒng)一的
DWRUtil.onReturn(event, submitFunction)
DWRUtil.selectRange
Selecting a range of text in an input box
You need to select text in an input box for any "Google suggest" type functions, however the selection model changes a lot between different browsers. The DWRUtil function to help here is: DWRUtil.selectRange(ele, start, end).
在一個(gè)input元素中選擇一個(gè)范圍的字符串,可以查看
http://getahead.ltd.uk/dwr/browser/util/selectrange操作
DWRUtil.setValue(id, value)
DWRUtil.setValue(id, value) finds the element with the id specified in the first parameter and alters its contents to be the value in the second parameter.
This method works for almost all HTML elements including selects (where the option with a matching value and not text is selected), input elements (including textareas) divs and spans.
主要是為了設(shè)值,屏蔽了select元素設(shè)值的問題,對(duì)select也可以方便的setvalue
DWRUtil.setValues()
Similar to setValue except that the input is a Javascript object that contains name/value pairs. The names are assumed to be the IDs of HTML elements, and the values, what we should set the contents of the elements.
與getValues對(duì)應(yīng),傳入js對(duì)象,將對(duì)象中的value傳給相應(yīng)的element
DWRUtil.toDescriptiveString(id,degree)
DWRUtil.toDescriptiveString is a better version of the toString() than the default. This function has a third parameter that declares the initial indent. This function should not be used from the outside world as it may well change in the future.
此函數(shù)主要用來調(diào)試,傳入元素的id,調(diào)試的degree將顯示DOM信息
此函數(shù)有第三個(gè)參數(shù),用于聲明初始化,包含第三個(gè)參數(shù)的調(diào)用不應(yīng)該為使用,因?yàn)檫@個(gè)函數(shù)將來會(huì)改變
DWRUtil.useLoadingMessage
You must call this method after the page has loaded (i.e. not before the onload() event has fired) because it creates a hidden div to contain the loading message.
你必須在頁面加載完成后(body onload事件)調(diào)用這個(gè)函數(shù),因?yàn)樗鼤?huì)創(chuàng)建一個(gè)div,來包含一些消息.類似gmail的message模式的東西.為了達(dá)到在頁面加載完成后來操作,
http://getahead.ltd.uk/dwr/browser/util/useloadingmessage
提供了一些方法.例如
<script>function init() { DWRUtil.useLoadingMessage();}if (window.addEventListener) { window.addEventListener("load", init, false);}else if (window.attachEvent) { window.attachEvent("onload", init);}else { window.onload = init;}</script>
該參考頁面給出了2個(gè)類似的文字圖片實(shí)現(xiàn).
DWRUtil.addOptions() 用返回的集合來填充select元素
多種實(shí)現(xiàn),詳細(xì)參考
http://getahead.ltd.uk/dwr/browser/listsDWRUtil.addRows() 返回的集合來填充table元素,或者tbody更為合適?
?