ajax
概述
這篇文章闡述了使用開源項目DWR(直接Web遠端控制)和AJAX(非同步JavaScript和XML)的概念來提高Web應用的可用性。作者一步步來展示DWR如何使得AJAX的應用既簡單又快捷。(1600字;2005年6月20日)
AJAX,或者說是非同步JavaScript和XML,描述了一種使用混合了HTML(或XHTML)和層疊樣式表作為表達資訊,來建立互動Web應用的開發技術;文件物件模型(DOM),JavaScript,動態地顯示和與表達資訊進行互動;並且,XMLHttpRequest對象與Web伺服器非同步地交換和處理資料。
網際網路上許多例子展示了在一個HTML檔案內部使用XMLHttpRequest與伺服器端進行互動的必要的步驟。當手工地編寫和維護XMLHttpRequest代碼時,開發人員必須處理許多潛在的問題,特別是類似於跨瀏覽器的DOM實現的相容性這樣的問題。這將會導致在編碼和調試Javascript代碼上面花費數不清的時間,這顯然對開發人員來說很不友好。
DWR(直接Web遠端控制)項目是在Apache許可下的一個開源的解決方案,它供給那些想要以一種簡單的方式使用AJAX和XMLHttpRequest的開發人員。它具有一套Javascript功能集,它們把從HTML頁面調用應用伺服器上的Java對象的方法簡化了。它操控不同類型的參數,並同時保持了HTML代碼的可讀性。
DWR不是對一個設計的插入,也不強迫對象使用任何種類的繼承結構。它和servlet架構內的應用配合的很好。對缺少DHTML編程經驗的開發人員來說,DWR也提供了一個JavaScript庫包含了經常使用的DHTML任務,如組裝表,用item填充select下拉框,改變HTML元素的內容,如<div>和<span>
DWR網站是詳盡的並且有大量的文檔,這也是這篇文章的基礎。一些例子用來展示DWR如何使用和用它的庫可以完成什麼樣的工作。
這篇文章讓讀者看到了一個使用了DWR的Web應用是如何一步步建立的。我會展示建立這個簡單的樣本應用的必要的細節,這個應用是可下載的並且可以在你的環境中布署來看看DWR如何工作。
注意:找到有關AJAX的資訊並不困難;網頁上有幾篇文章和部落格的條目涵蓋了這個主題,每一個都試圖指出和評論這個概念的不同的方面。在資源部分,你會找到一些有趣的指向樣本和文章的連結,來學習AJAX的更多的內容。
樣本應用
這篇文章使用的樣本應用類比了多倫多的一個公寓出租搜尋引擎。使用者可以在搜尋前選擇一組搜尋標準。為了提高互動性,AJAX中以下兩種情況下使用:
·應用通告使用者配合他的選擇會返回多少搜尋結果。這個數字是即時更新的-使用AJAX-當使用者選擇的臥室和浴室的數量,或者價格範圍變化時。當符合標準的搜尋結果沒有或太多時,使用者就沒有必要點擊搜尋按紐。
·資料庫查詢並取回結果是由AJAX完成的。當使用者按下顯示結果按鈕時,資料庫執行搜尋。這樣,應用看起來更具響應了,而整個頁面不需要重載來顯示結果。
資料庫
我們使用的資料庫是HSQL,它是一種佔用資源很小的Java SQL資料庫引擎,可以不需要安裝和配置的與Web應用捆綁在一起。一個SQL檔案被用來在Web應用的上下文啟動時建立一個記憶體中的表並添加一些記錄。
Java類
應用程式套件含了兩個主要的類叫Apartment和ApartmentDAO。Apartment.java類是一個有著屬性和getter/setter方法的簡單的Java類。ApartmentDAO.java是資料訪問類,用來查詢資料庫並基於使用者的搜尋標準來返回資訊。ApartmentDAO類的實現的直接了當的;它直接使用了Java資料庫聯結調用來得到公寓的總數和符合使用者請求的可用公寓的列表。
DWR配置和使用
設定DWR的使用是簡單的:將DWR的jar檔案拷入Web應用的WEB-INF/lib目錄中,在web.xml中增加一個servlet聲明,並建立DWR的設定檔。DWR的分發中需要使用一個單獨的jar檔案。你必須將DWR servlet加到應用的WEB-INF/web.xml中布署描述段中去。
<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>
一個可選的步驟是設定DWR為偵錯模式—象上面的例子那樣—在servlet描述段中將debug參數設為true。當DWR在偵錯模式時,你可以從HTMl網頁中看到所有的可訪問的Java對象。包含了可用對象列表的網頁會出現在/WEBAPP/dwr這個url上,它顯示了對象的公用方法。所列方法可以從頁面中調用,允許你,第一次,運行伺服器上的對象的方法。下圖顯示了調試頁的樣子:
調試頁
現在你必須讓DWR知道通過XMLHttpRequest對象,什麼對象將會接收請求。這個任務由叫做dwr.xml的設定檔來完成。在設定檔中,定義了DWR允許你從網頁中調用的對象。從設計上講,DWR允許訪問所有公布類的公用方法,但在我們的例子中,我們只允許訪問幾個方法。下面是我們樣本的設定檔:
<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>
上面的檔案實現了我們例子中的兩個目標。首先,<convert>標記告訴DWR將dwr.sample.Apartment對象的類型轉換為聯合數組,因為,出於安全的原因,DWR預設的不會轉換普通bean。第二,<create>標記讓DWR暴露出dwr.sample.ApartmentDAO類給JavaScript調用;我們在頁面中使用JavaScript檔案被javascript屬性定義。我們必須注意<include>標記,它指明了dwr.sample.ApartmentDAO類的哪些方法可用。
HTML/JSP代碼
配置完成後,你就可以啟動你的Web應用了,這時DWR會為從你的HTML或Java伺服器端頁面(JSP)上調用所需方法作好準備,並不需要你建立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>
我們注意到當使用者改變搜尋標準時,這是AJAX在樣本程式中的首次應用;正如他所看到的,當標準改變時,可用的公寓數量被更新了。我建立了兩個JavaScript函數:當某一個選擇下拉框中的值變化時被調用。ApartmentDAO.countApartments()函數是最重要的部分。最有趣的是第一個參數, loadTotal()函數,它指明了當接收到服務端的返回時DWR將會調用的JavaScript方法。loadTotal於是被調用來在HTML頁面的<div>中顯示結果。下面是在這個互動情境中所使用到的JavaScript函數:
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;}
很明顯,使用者想看到符合他的搜尋條件的公寓列表。那麼,當使用者對他的搜尋標準感到滿意,並且總數也是有效話,他會按下顯示結果的按紐,這將會調用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()方法清空了存放搜尋返回結果的表域,從使用者介面上擷取所需參數,並且將這些參數傳給DWR建立的ApartmentDAO對象。然後資料庫查詢將被執行,fillTable()將會被調用,它解析了DWR返回的對象(apartment),然後將其顯示到頁面中(apartmentsbody)。
安全因素
為了保持樣本的簡要,ApartmentDAO類儘可能的保持簡單,但這樣的一個類通常有一組設定方法來操作資料,如insert(), update()和delete()。DWR暴露了所有公用方法給所有的HTML頁面調用。出於安全的原因,像這樣暴露你的資料訪問層是不明智的。開發人員可以建立一個門面來集中所有JavaScript函數與底層業務組件之間的通訊,這樣就限制了過多暴露的功能。