FireBug ajax

原文地址:http://www.joehewitt.com/software/firebug/docs.php
FireBug 是一個非常實用的JavaScript以及DOM查看調試工具,是 Firefox 的一個插件。使用 FireBug 調試 AJAX 應用非常方便,終於可以告別 alert 時代了!

Console Logging 函數

FireBug 爲所有 Web 頁面提供了一個 console 對象。這個對象有以下函數:

Logging 基礎

console.log("message" [,objects]) - 將一個字符串打印到控制檯。字符串可以包含任何“String Formatting”小節描述的模式。字符串後面的對象應該用來取代之前字符串中的模式。(譯者注:大家用過C裏面 printf 吧,效果基本是一樣的。)

Logging 等級

通常根據不同的等級來區分Logging的嚴重程度是很有幫助的。FireBug 提供了4個等級。爲了達到視覺分離的效果,這些函數與 log 不同的地方就是它們在被調用的時候會自動包含一個指向代碼行數的鏈接。

console.debug("message" [,objects]) - 記錄一個 debug 消息。
console.info("message" [,objects]) - 記錄一個信息.
console.warn("message" [,objects]) - 記錄一個警告.
console.error("message" [,objects]) - 記錄一個錯誤.

斷言

斷言是一條確保代碼規則的非常好的途徑。console 對象包含了一系列各種類型的斷言函數,並且允許你編寫自己的斷言函數。

console.assert(a, "message" [,objects]) - Asserts that an a is true.
console.assertEquals(a, b, "message" [,objects]) - Asserts that a is equal to b.
console.assertNotEquals(a, b, "message" [,objects]) - Asserts that a is not equal to b.
console.assertGreater(a, b, "message" [,objects]) - Asserts that a is greater than b.
console.assertNotGreater(a, b, "message" [,objects]) - Asserts that a is not greater than b.
console.assertLess(a, b, "message" [,objects]) - Asserts that a is less than b.
console.assertNotLess(a, b, "message" [,objects]) - Asserts that a is not less than b.
console.assertContains(a, b, "message" [,objects]) - Asserts that a is in the array b.
console.assertNotContains(a, b, "message" [,objects]) - Asserts that a is not in the array b.
console.assertTrue(a, "message" [,objects]) - Asserts that a is equal to true.
console.assertFalse(a, "message" [,objects]) - Asserts that a is equal to false.
console.assertNull(a, "message" [,objects]) - Asserts that a is equal to null.
console.assertNotNull(a, "message" [,objects]) - Asserts that a is not equal to null.
console.assertUndefined(a, "message" [,objects]) - Asserts that a is equal to undefined.
console.assertNotUndefined(a, "message" [,objects]) - Asserts that a is not equal to undefined.
console.assertInstanceOf(a, b, "message" [,objects]) - Asserts that a is an instance of type b.
console.assertNotInstanceOf(a, b, "message" [,objects]) - Asserts that a is not an instance of type b.
console.assertTypeOf(a, b, "message" [,objects]) - Asserts that the type of a is equal to the string b.
console.assertNotTypeOf(a, b, "message" [,objects]) - Asserts that the type of a is not equal to the string b.

測量(Measurement)

下面的一些函數可以讓你方便的測量你的一些代碼。

console.trace() - 記錄執行點的堆棧信息。
console.time("name") - 根據 name 創建一個唯一的計時器。
console.timeEnd("name") - 根據 name 停止計時器,並且記錄消耗的時間,以毫秒爲單位。
console.count("name") - 記錄該行代碼執行的次數。

字符串格式化

所有 console 的 logging 函數都可以通過以下模式格式化字符串:

%s - 將對象格式化爲字符串。
%d, %i, %l, %f - 將對象格式化爲數字。
%o - 將對象格式化成一個指向 inspector 的超鏈接。
%1.o, %2.0, etc.. - 將對象格式化成包含自己屬性的可交互的表格。
%.o - 將對象格式化成具有自身屬性的一個數組。
%x - 將對象格式化成一個可交互的 XML 樹形結構。
%1.x, %2.x, etc.. - 將對象格式化成一個可交互的 XML 數型結構,並且展開 n 層節點。

如果你需要一個真實的 % 符號,你可以通過一個轉移符號就像這樣 "/%"。

命令行函數

內建的命令行函數可以通過以下命令行使用:

$("id") - document.getElementById() 的簡寫。(譯者注:跟 prototype.js 學來的吧?)
$$("css") - 返回一個符合 CSS 選擇器的元素數組。
$x("xpath") - 返回一個符合 XPath 選擇器的元素數組。
$0 - 返回最近被檢查(inspected)的對象。
$1 - 返回最近被檢查(inspected)的下一個對象。
$n(5) - 返回最近被檢查的第n個對象。
inspect(object) - 將對象顯示在 Inspector 中。
dir(object) - 返回一個對象的屬性名數組。(譯者注:跟 Python 學的?)
clear() - 清除控制檯信息。

Posted in JavaScript, Ajax, Web應用 | 3 Comments »

編寫自己的dojo擴展

Posted by Nicholas Ding on 12th 八月 2006

前言

dojo是時下非常流行的javascript框架,它在自己的Wiki上給自己下了一個定義,dojo是一個用JavaScript編寫的開源的DHTML工具箱。

dojo很想做一個“大一統”的工具箱,不僅僅是瀏覽器層面的,野心還是很大的。不過dojo帶來了JavaScript編程的一些新想法,其中引入包機制進行動態加載是一個不錯的概念。

理解dojo的包機制

其實dojo只需要一些很小的加載代碼就可以用來加載它的各種包,它的官方站點上提供的dojo-ajax下載中包含的dojo.js體積還是比較龐大的,因爲它將一些常用的包都包含在了js中, 但是很多時候我們並不需要這麼多功能,還是按需加載比較好。

幸好在http://download.dojotoolkit.org/這個地址中我們還可以下載到dojo的各個自定義版本,其實包含的組件都是一樣的,只不過dojo.js的大小有很大不同,那麼,我們就從minimal版本下手。

下載之後會發現minimal版本包含的dojo.js只有18kb,裏面僅僅包含了加載機制,非常不錯。這樣,我們就可以開始編寫自己的dojo擴展。

dojo代碼結構

解壓縮後的目錄裏面包含src目錄,src目錄下存放有dojo的各個組件包,我們在這裏面新建一個hello目錄。

新建一個名爲__package__.js文件,很類似Python的模塊命名,這個__package__.js定義了在引入這個命名空間的時候默認導入多少類,以及這個命名空間的名字。

我們的目的是做一個dojo.hello.Echo擴展,那麼在__package__.js中的代碼應該這樣:

// kwCompoundRequire 的作用是當你導入整個dojo.hello包的時候需要默認加載多少類
// 這些定義就在這個函數裏面,common在這裏表示默認的加載,這個參數不是固定的
// dojo希望自己是一個“大一統”的實現,所以考慮了非瀏覽器情況,可以有別的,譬如rhino
dojo.kwCompoundRequire({
	common: [
		"dojo.hello.Echo"
	]
});
// 這個定義了包,默認這麼寫 | 原因嘛,當然是有的,看你的悟性了:-)
dojo.provide("dojo.hello.*");

我們指定了默認加載的類Echo,那麼我們就去寫Echo類,在hello目錄中新建Echo.js,代碼如下:

// 類名定義,JavaScript寫的變扭,其實就是直接定義類名
dojo.provide("dojo.hello.Echo");
 
// 類定義部分,非常熟悉的代碼
dojo.hello.Echo = function() {
	this.name = "dojo.hello.Echo";
	this.sayHello = function(greeting) {
		return greeting;
	}
}

擴展寫好了,很簡單,接下來就是掉用了,index.html如下。

<html>
<head>
<script language="javascript" src="dojo.js"></script>
<script language="javascript">
dojo.require("dojo.hello.*");
var echo = new dojo.hello.Echo();
document.write(echo.sayHello("Hello World"));
</script>
</head>
<body>

</body>
</html>

注意dojo.require("dojo.hello.*")回去請求兩個文件,首先是__package__.js,這樣一來就得到了之前在dojo.kwCompoundRequire裏面指定的類列表,然後去加載Echo.js。你也可以直 接去加載Echo.js,只需要變成dojo.require("dojo.hello.Echo")

更多內容

這個例子非常簡單的介紹了一下dojo的包加載機制,當然這個包中的類並沒有引用其它類,dojo還允許在代碼中動態加載其它類,當然了,這些都是通過XmlHttp來實現的,因爲是同步模式,所以請求的類比較多並且都沒有包含在dojo.js中的時候會有頁面停頓的現象,這點還是需要注意的。

文中的代碼下載:,dojo-hello.tar.gz

一些dojo的資源:

Posted in JavaScript, Ajax, Web應用 | No Comments »

AJAX 入門

Posted by Nicholas Ding on 17th 五月 2006

AJAX in Action

像其他人一樣,當我看到一下RIA應用,例如Google Maps和Google Suggest的時候我都非常驚訝。我希望知道是如何實現的。現在,謎底揭開了,那就是AJAX。這是在我花了一段時間研究AJAX之後才知曉的。這裏有一個很好的例子讓我們知道AJAX是如何很好的應用在 JavaRSS.com 裏面的。

什麼是AJAX:
AJAX 是一個架構(architecture)並不是一種技術。AJAX代表異步的JavaScript和XML。
妙語(Punch Line):
延遲加載
問題:
當JavaRSS.com首頁加載時,他同時加載了所有條目的介紹(如果你在設置中激活了)。這些介紹只有當你鼠標移動到該條目的上面的時候才顯示。

現在的問題是用戶不可能是鼠標移過所有的條目,所以預先加載所有的介紹不是個好主意。

解決方案: 使用AJAX,當鼠標移過的時候從服務器動態加載條目的介紹。

這麼做可以使初始頁的加載大小減小一半甚至更多,這樣一來頁面加載就更快,就內能得到一個更好的用戶體驗。

時序圖:

AJAX Sequence Diagram

我們首先會在onmouseover事件中調用JavaScript函數getDescription。下面是html代碼:

<a href="/" οnmοuseοver="getDescription(3,1)">Java & J2EE News</a>

下面是 getDescription 函數的代碼:

var url = 'http://localhost:8080/getDescription.jsp?channelId=' + channelId + '&itemId=' + itemId;
    if (window.XMLHttpRequest) {
        req = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        req = new ActiveXObject("Microsoft.XMLHTTP");
    }
    req.onreadystatechange = processRequest;
    req.open("GET", url, true);
    req.send(null);

XMLHttpRequest 對象將用來進行http連接並取回xml文檔。我們需要檢測一下是否是IE並且創建 XMLHttpRequest 對象。

if (window.XMLHttpRequest) {
        req = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        req = new ActiveXObject("Microsoft.XMLHTTP");
    }

設置回調函數,並且發送"GET"請求至服務器接收xml文檔:

req.onreadystatechange = processRequest;
    req.open("GET", url, true);
    req.send(null);

JSP將根據適當的條目編號創建具有相應介紹的xml文檔。

<%
String channelId = request.getParameter("channelId");
String itemId = request.getParameter("itemId");
//String description = new Channel(channelId).getItemDescription(itemId);
String description = "This is the description for the channelId: " + channelId + "and itemId: " + itemId;
 
if (description != null) {
   response.setContentType("text/xml");
   response.setHeader("Cache-Control", "no-cache");
   response.getWriter().write("<description>" + description.toString() + "</description>");
} else {
   //nothing to show
   response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
%>

檢測HTTP請求返回狀態碼,狀態爲200,即OK。

function processRequest() {
    if (req.readyState == 4) {
        if (req.status == 200) {
          parseMessages();
        } else {
  alert ( "Not able to retrieve description" );
        }
    }
}

readyState = 4 的情況下文檔被加載。

readyState Status Codes:
  • 0 = uninitialized
  • 1 = loading
  • 2 = loaded
  • 3 = interactive
  • 4 = complete

最後,我們解析XML文檔並顯示介紹。

問題: 唯一的問題就是我遭遇到的 "&" 字符。 "&" 在XML文檔裏面不是一個有效字符。所以我需要將他轉換成 "&amp;"。

function parseMessages() {
	response  = req.responseXML.documentElement;
	itemDescription = response.getElementsByTagName('description')[0].firstChild.data;
	alert(itemDescription);
}

下面是所有的代碼:

HTML Code:
<a href="/" οnmοuseοver="getDescription(3,1)">Java & J2EE News<a>
JavaScript Code:
function getDescription(channelId,itemId) {
    var url = 'http://localhost:8080/getDescription.jsp?channelId=' + channelId + '&itemId=' + itemId;
    if (window.XMLHttpRequest) {
        req = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        req = new ActiveXObject("Microsoft.XMLHTTP");
    }
    req.onreadystatechange = processRequest;
    req.open("GET", url, true);
    req.send(null);
}
 
function processRequest() {
    if (req.readyState == 4) {
        if (req.status == 200) {
          parseMessages();
        } else {
          alert ( "Not able to retrieve description" );
				}
    }
}
 
function parseMessages() {
	response  = req.responseXML.documentElement;
	itemDescription = response.getElementsByTagName('description')[0].firstChild.data;
	alert ( itemDescription );
}
JSP Code:
<%
String channelId = request.getParameter("channelId");
String itemId = request.getParameter("itemId");
description = "This is the description for the channelId: " + channelId + "and itemId: " + itemId;
 
if (description != null) {
   response.setContentType("text/xml");
   response.setHeader("Cache-Control", "no-cache");
   response.getWriter().write("<description>" + description.toString() + "</description>");
} else {
   //nothing to show
   response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
%>

資源:

使用AJAX的Google站點:

關於作者:

  • Jay 具有10年以上的IT工作經驗,並且自從Java & J2EE誕生那天起就開始接觸他們了。
  • 譯者Nicholas@NirvanaStudio

Posted in Ajax | No Comments »

在Java2平臺企業版中應用異步JavaScript技術和XML(AJAX)

Posted by ShiningRay on 3rd 四月 2006

作者Greg Murray, 2005年6月9日June 9, 2005  翻譯:ShiningRay@Nirvana Studio2005年9月9日
任何試過過Flickr、GMail、Google Suggest或者是Google Maps的人都會意識到一種新型的動態Web應用正在逐漸浮出水面。這些應用外觀和表現都和傳統的桌面應用程序很像,而他們不需要依賴於插件或者是特定於瀏覽器的功能。過去Web應用只是一系列HTML頁面,他們任意一部份內容的更改都必須重新載入頁面。像JavaScript編程語言和層疊樣式表 (CSS)之類的技術已經成熟,可以有效地應用他們來創建高動態的Web應用,而且可以運行在所有的主流瀏覽器中。本文將會詳細介紹你馬上就可以使用的一些技術,讓他們使你的Web應用像桌面應用更加豐富和更有交互性。

介紹異步JavaScript技術和XML(AJAX)


使用JavaScript技術,一個HTML頁面可以異步地對服務器(一般是載入頁面的服務器)發送請求並獲取XML文檔。然後JavaScript可以使用XML文檔來更新或改動HTML頁面的文檔對象模型(DOM)。最近形成了一個術語AJAX(Asynchronous JavaScript Technology and XML)來描述這種交互模型。

AJAX其實不是很新的東西。這些技術對於Windows平臺上專注於Internet Explorer的開發人員來說,已經存在好幾年了。直到最近,這個技術才被作爲Web遠程技術或者遠程腳本技術被大家瞭解。Web開發人員也有一段時間曾經使用過插件、Java applet和隱藏框架來模擬這種交互模型。最近發生的變化是,對XMLHttpRequest對象的支持已經成爲所有平臺上的主流瀏覽器都包括的特性了。JavaScript技術的XMLHttpRequest對象是。儘管在正式的JavaScript技術標準中並沒有提到這種對象,然而今天主流的瀏覽器都對他提供了支持。而當代的瀏覽器如Firefox、Internet Explorer以及Safari在JavaScript技術和CSS的支持上有些細微的差別,但是這種差別是可以處理的。如果你要考慮支持較老的瀏覽器,AJAX也許就不能成爲你的解決方法。

基於AJAX的客戶端之所以獨特的原因是客戶端包含了用JavaScript嵌入的特定於頁面的控制邏輯。應用JavaScript技術的頁面基於事件進行交互,如文檔載入、鼠標點擊、焦點改變甚至是定時器。AJAX交互使得表現層邏輯更加清晰地與數據分離。一個HTML頁面也可以根據需要每次讀入適當的數據,而不是每次需要顯示一個更改時都重新載入整個頁面。AJAX要求一種不同的服務器架構來支持它這種交互模型。以前,服務器端Web應用關注於對每個導致服務器調用的客戶端事件都生成HTML文檔。然後客戶端對每個迴應都要重新讀入並重新渲染完整的HTML頁面。富Web應用(Rich Web Application)關注於,讓一個客戶端獲取一個HTML文檔讓它表現爲一個模板或者是一個容器,可以基於事件並使用從服務器端組件中獲取的XML 數據來對文檔注入內容。

一些AJAX交互的應用如:

  • 實時表單數據檢驗:像用戶ID、序列號、郵政編碼或者是特殊的票據代碼這類需要服務器端驗證的數據也可以在用戶提交表單之前進行驗證。
  • 自動補全:像電子郵件地址、姓名或城市名之類的表單數據都可以根據用戶情況自動補全。
  • 處理細節操作:根據一個客戶端事件,一個HTML頁面可以根據現存的一些數據再去獲取更多詳細的信息,如現在有一個產品列表,客戶端可以控制查看單獨的產品信息而無需刷新頁面。
  • 複雜的用戶界面控件:像樹型控件、菜單和進度條之類不要求頁面刷新的控件也能實現。
  • 頁面內刷新數據:HTML頁面可以從服務器上查詢最新的數據如分數、股指、天氣還有其它的特定於應用的數據。
  • 服務器端通知:一個HTML頁面可以通過對服務器進行定時查詢來模擬一個服務器的事件通知推送,實現像通知客戶端一個消息、刷新頁面數據或將客戶端重定向到另一個頁面。

這個列表並未把所有的應用都列出來,但它已經顯示了AJAX交互可以讓Web應用比從前能做更多的事情。但儘管這些好處是值得關注的,這種方式也有一些缺點:

  • 複雜度:服務器端開發人員必需理解,HTML客戶端頁面中的表現層邏輯以及生成HTML客戶端頁面所需的XML內容的服務器端邏輯。HTML頁面開發人員必須瞭解JavaScript技術。如果開發新的框架和發展已有的框架來支持這種交互模型,那麼AJAX應用的創建就會越來越簡單。
  • XMLHttpRequest對象的標準化:XMLHttpRequest對象還不是JavaScript技術標準的一部分,這就意味着根據客戶端的不同,應用的行爲也有所會不同。
  • JavaScript技術的實現:AJAX交互極大地依賴於JavaScript技術,而由於客戶端的原因JavaScript還有一些細微的差別。見QuirksMode.org來了解更多關於瀏覽器之間區別的內容。
  • 調試:AJAX應用也難於調試,因爲流程邏輯是同時嵌在客戶端中和服務器上的。
  • 代碼可見:客戶端的JavaScript可以很容易通過“查看源代碼”被人看見。一個沒有良好設計的AJAX應用很可能被黑客攻擊或被他人剽竊。

當開發人員在使用AJAX交互模型上獲得更多的經驗後,AJAX技術的框架和模式就會慢慢浮現出來。現在就關注於完全通用的AJAX交互框架,還爲時過早。本文和相關的解決方案將關注於在現有的Java 2平臺企業版(J2EE)上如何對AJAX進行支持,像servlet,JavaServer Page(JSP)軟件、JavaServer Face應用和Java標準標籤庫(JSTL)。

AJAX交互剖析


現在我們已經討論了AJAX是什麼以及一些高層次的問題。那現在讓我們把所有的零件放在一起來展示一個具有AJAX的J2EE應用。

首先考慮一個例子。一個Web應用包括了一個靜態HTML頁面,或者是一個由JSP生成的HTML頁面,這個JSP中還包括了一個HTML表單,它需要服務器端邏輯來對錶單中的數據進行檢驗,而不用刷新頁面。一個名爲ValidateServlet服務器端組件(servlet)用來提供這種驗證邏輯。圖一描述了這種具有驗證邏輯的AJAX交互的細節。

AJAX Interaction
圖1: 一個提供驗證邏輯的AJAX交互

以下條目代表了圖1中出來AJAX交互的過程:

  1. 發生一個客戶端事件
  2. 創建和配置一個XMLHttpRequest對象。
  3. XMLHttpRequest對象進行一個調用。
  4. ValidateServlet對請求進行處理。
  5. ValidateServlet返回一個包含了結果的XML文檔。
  6. XMLHttpRequest對象調用callback()函數並處理結果。
  7. 更新 HTML DOM。

現在讓我們逐個研究這個AJAX模型的每一步。

1.發生一個客戶端事件。

在一個事件發生時可以調用相應的JavaScript函數。在這裏,validate()函數可以被映射到一個鏈接或者是表單組件的onkeyup事件上去。

<input type="text"
    size="20"
    id="userid"
    name="id"
    οnkeyup="validate();">

每次用戶在表單域中按下一個鍵時,表單元素將都調用validate()函數。 

2. 建立和配置一個XMLHttpRequest對象

創建和配置一個XMLHttpRequest對象

var req;
 
function validate() {
    var idField = document.getElementById("idField");
    var url = "validate?id=" + escape(idField.value);
    if (window.XMLHttpRequest) {
        req = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        req = new ActiveXObject("Microsoft.XMLHTTP");
    }
    req.open("GET", url, true);
    req.onreadystatechange = callback;
    req.send(null);
}

validate()函數建立了一個XMLHttpRequest對象並對象中的open函數。open函數需要兩個參數:HTTP方法,可以是GETPOST; 和對象進行交互的服務器端組件的URL;一個布爾變量,表示是否要進行異步調用。API是XMLHttpRequest.open(String method, String URL, boolean asynchronous)。如果一個交互被設置爲異步, (true) 那就必須指明一個回調函數。可以使用req.onreadystatechange = callback;來設置這個交互的回調函數。詳細內容見第六節。

3.XMLHttpRequest對象進行調用

當收到了語句req.send(null);,就會進行一次調用。HTTPGET的情況下,內容可以是null或者留空。當調用XMLHttpRequest的這個函數時,也會對已經配置了的URL進行調用。在下面這個例子中,要發送的數據(id)將作爲一個URL參數。

使用HTTPGET,兩個重複的請求將返回同樣的結果。當使用HTTPGET方法時,要注意URL的長度,包括已經轉義的URL參數,可能會受到某些瀏覽器和服務器端的Web容器的限制。當發送的數據會影響到服務器端的應用程序的狀態時,就應該使用HTTPPOST方法。使用HTTPPOST必須要對XMLHttpRequest對象設置一個Content-Type頭,使用以下語句:

req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
req.send("id=" + escape(idTextField.value));

當從JavaScript中發送表單值得時候,你應該考慮對字段值進行編碼。JavaScript中有一個函數escape(),應該用他來確保區域化的內容被正確編碼,同時特殊字符也被正確轉義。

4. ValidateServlet對請求進行處理.

一個映射到URI "validate" 的servlet將檢驗user ID是不是已經在數據庫中存在了。

一個servlet處理一個XMLHttpRequest ,就像對待其它的HTTP請求一樣。下面的例子顯示了服務器從請求中抽取出id參數並檢驗是否被佔用了。

public class ValidateServlet extends HttpServlet {
 
    private ServletContext context;
    private HashMap users = new HashMap();
 
    public void init(ServletConfig config) throws ServletException {
        this.context = config.getServletContext();
        users.put("greg","account data");
        users.put("duke","account data");
    }
 
    public void doGet(HttpServletRequest request, HttpServletResponse  response)
    throws IOException, ServletException {
 
        String targetId = request.getParameter("id");
 
        if ((targetId != null) && !users.containsKey(targetId.trim())) {
            response.setContentType("text/xml");
            response.setHeader("Cache-Control", "no-cache");
            response.getWriter().write("<message>valid</message>");
        } else {
            response.setContentType("text/xml");
            response.setHeader("Cache-Control", "no-cache");
            response.getWriter().write("<message>invalid</message>");
        }
    }
}

在這個例子中,一個簡單的HashMap用來存放存在的用戶名。在這個例子中,我們假設用戶的ID是duke

5.ValidateServlet返回一個包含結果的XML文檔

用戶ID "duke" 在users HashMap的用戶ID列表中出現了。將在應答中寫一個包含值爲invalidmessage元素的XML文檔。更復雜的用例將要求DOM、XSLT或其他API來生成這個應答。

response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
response.getWriter().write("<message>invalid</message>");

開發人員必須注意兩個事情。第一,Content-Type必須設爲text/xml。第二,Cache-Control必須設爲no-cacheXMLHttpRequest對象只會處理Content-Typetext/xml的應答,同時把將Cache-Control設爲no-cache將確保瀏覽器不會從緩存相同的URL(包括參數)返回的應答。

6.XMLHttpRequest對象調用callback()函數並處理結果。

XMLHttpRequest對象已經配置爲當有readyState改變的時候就調用callback()函數。讓我們假設已經ValidateServlet調用了而且ValidateServlet4,表示XMLHttpRequest的調用已經完成。HTTP狀態代碼200表示一個成功的HTTP交互。

function callback() {
if (req.readyState == 4) {
    if (req.status == 200) {
        // update the HTML DOM based on whether or not message is valid
    }
}
}

瀏覽器維護了一個所顯示的文檔的對象形式(也就是所謂的Docuemt Object Model或DOM)。HTML頁面中的JavaScript可以訪問DOM,同時在頁面載入完之後,可以使用API來修改DOM。

根據成功的請求,JavaScript代碼可以修改HTML頁面的DOM。從ValidateServlet獲得的對象形式的XML文檔可以通過req.responseXML在JavaScript中獲得,req是一個XMLHttpRequest對象。DOM API給JavaScript提供了獲取這個文檔中的內容以及修改HTML頁面的DOM的方法。所返回的字符串形式的XML文檔可以通過req.responseText獲得。現在我們看看如何在JavaScript中使用DOM API,先看以下從ValidateServlet返回的XML文檔。

<message>
valid
</message>

這個例子是一個簡單的只包含了一個message元素的XML片斷,裏面只有一個簡單的字符串validinvalid。一個更高級的例子可以包含多於一個的消息和可以給用戶看的有效的名字:

function parseMessage() {
    var message = req.responseXML.getElementsByTagName("message")[0];
    setMessage(message.childNodes[0].nodeValue);
}

parseMessages()函數將處理一個從ValidateServlet獲取的XML文檔。這個函數會調用setMessage()with the,並給出message作爲參數來更新HTML DOM。

7.更新HTML DOM

JavaScript技術可以使用很多API從HTML DOM中獲得任何元素對象的引用。推薦的獲得元素引用的方法是調用document.getElementById("userIdMessage")"userIdMessage"是HTML文檔中出現的一個元素的ID屬性。有了這個元素的引用,就可以使用JavaScript來修改元素的屬性、修改元素的樣式、添加、刪除或修改子元素。

一個常見的改變元素主體內容的方法是設置元素的innerHTML屬性,如下所示:

<script type="text/javascript">
function setMessage(message) {
    var userMessageElement = document.getElementById("userIdMessage");
    userMessageElement.innerHTML = "<font color=/"red/">" + message + " </font>";
}
</script>
<body>
<div id="userIdMessage"></div>
</body>

受到影響的那部分HTML頁面會立刻根據innerHTML的設置重新渲染。如果innerHTML屬性包含類似<image>或者是<iframe>之類的元素,那麼由那些元素所指定的內容同樣會被獲取並渲染。

這種途徑的主要缺點是HTML元素是作爲字符串硬編碼在JavaScript中的。JavaScript中硬編碼的HTML標記不是一種好的實踐,因爲它使代碼難於閱讀、維護和修改。我們應該考慮在JavaScript中使用DOM API來創建和修改HTML元素。把顯示和JavaScript代碼的字符串混在一起只會讓頁面更難於閱讀和編輯。

另一種修改HTML DOM的方法是動態地產生新的元素並把他們作爲子元素追加到目標元素,如下面的例子所示:

<script type="text/javascript">
function setMessage(message) {
    var userMessageElement = document.getElementById("userIdMessage");
    var userIdMessageFont = document.getElementById("userIdMessageFont");
    var messageElement = document.createTextNode(message);

    if (userMessageElement.childNodes[0]) {
        // 更新元素
        userIdMessageFont.replaceChild(messageElement, userIdMessageFont.childNodes[0]);
    } else {
        // 建立一個新的元素
        var fontElement = document.createTextNode("font");
        fontElement.setAtribute("id", "userIdMessageFont");
        fontElement.setAtribute("color", "red");
        userMessageElement.appendChild(fontElement);
        fontElement.appendChild(messageElement);
    }
}
</script>
<body>
<div id="userIdMessage"></div>
</body>

這個範例展示了JavaScript技術的DOM API可以用來更有目的地建立或改變一個元素。當然JavaScript的DOM AP在不同的瀏覽器上也可能有差別,所以你必須在開發應用程序時小心。

Java BluePrint的解決方案目錄

TheJava Blueprints Solutions Catalog是用來收集J2EE技術上AJAX的最佳實踐的。每個解決方案包含一個問題和方法的描述、一個設計文檔和可運行的源碼。這些解決方案是爲了讓你根據需要在自己的應用程序中複用。以下是已經提供的AJAX交互:

自動補全

自動補全提供了當用戶在一個HTML表單中輸入一個請求時對數據瀏覽的簡化方式。當用戶面對一大片數據時,可以在輸入數據時把可能的完整形式顯示給用戶。然後選擇其中一個完整形式可以保證用戶輸入的數據已經存在在服務器上。

考慮一個大公司的一個名字查找的Web應用。如圖2所示,只要輸入姓或名的開頭幾個字母就可以得到人的列表。用戶可以然後就只要點擊一下就可以瀏覽用戶的詳細信息。

Autocompletion of a Name
圖2:名字自動補全

進度條

在Web應用中,一個服務器端任務也可能要花一段時間去完成。這段時間很可能會超過HTTP交互的時間上限(超時)。當用戶不知道這個任務什麼時候才能完成時,用戶很可能會重新提交一次表單或直接退出會話狀態。一般來說,Web應用使用頁面刷新來跟蹤服務器端操作的狀態,這種方式可能會讓人厭煩而且也不準確。AJAX可以用來僅在一個HTML頁面中跟蹤服務器端操作的狀態而無需刷新頁面。用戶可以以圖形方式看到服務器端操作的進度,如圖3。

Progress Bar
圖3:進度條 

刷新數據

向一個HTML頁面提供最新的數據或服務器消息提醒在現在的Web世界中也是十分重要的,因爲現在的Web世界中數據一直不停變化。儘管它不是一個實實在在的推送技術,但它可以通過使用AJAX交互不斷進行查詢來模擬。當數據需要更新或者要進行提醒,HTML頁面將會動態地改變。圖4顯示了HTML頁面中的一個服務器端計數器。這個計數器會在頁面後臺自動更新。

Server-side Counter Shows Refreshing Data
圖4:服務器端計數器在刷新數據

實時檢驗

不是所有的表單域都可以單獨用JavaScript技術在客戶端完成。某些表單數據要求服務器端的驗證邏輯。傳統和Web應用曾使用頁面刷新來完成這種驗證,但這可能有些讓人煩。

考慮一個需要一個唯一用戶ID的Web應用。使用AJAX交互,用戶可以在輸入的時候就知道ID是否有效(圖5)。

Invalidating the ID as User Types
圖5:指出用戶ID無效

當一個用戶輸入了一個無效的用戶ID,應用程序禁止了提交按鈕並且向用戶顯示了一個信息(圖6)。

Validating the ID as User Types
圖6:用戶ID通過驗證

用戶馬上就能知道用戶ID是可用的也是有效的。


最後的思考

我們已經看到AJAX交互可以解決很多問題。配合HTTP處理、數據庫、Web服務、XML處理和業務對象等API,J2EE技術已經提供了一個開發和部屬基於AJAX應用的一個良好的基礎。有了對於這個交互模型的更好的理解,今天的應用程序可以變得更加有交互性,給最終用戶更好的體驗。

使用AJAX要求你使用支持XMLHttpRequest對象的最新瀏覽器版本。使用AJAX還要求大量對JavaScript技術和CSS的應用。作爲一個應用程序架構師或是一個開發人員,你要會針對瀏覽器支持、架構複雜度和對開發人員的培訓等方面來衡量開發一個富應用的需要。當AJAX編程模型不斷地發展,現有的技術和框架會讓這種轉變更加容易。

很明顯的是,突出的Web應用都越來越有交互性了。那麼你的呢?


更多信息

關於作者

Greg Murray 是is a Sun Microsystems 的一名工程師,是servlet標準的領導人,BluePrint小組的前成員,在這個小組時他已經開始關注Web層次問題。他也是《Enterprise Applications With the Java 2 Platform,Enterprise EditionDesigning Web Services With the J2EE 1.4 Platform(Addison-Wesley)》一書的協助編撰者。 

發佈了41 篇原創文章 · 獲贊 5 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章