從2005年開始,ajax在全球漸漸掀起了一股潮流,它使瀏覽器可以為用戶提供更為自然的瀏覽體驗,全球幾百個ajax項目中,dwr就是其中一項。
ajax采用的技術基石其實早就有了,就是“無刷新訪問服務器”技術,所以有人說ajax其實就是新瓶裝老酒,一點沒錯,就是新瓶裝老酒,在工程師們將“無刷新訪問服務器”技術封裝成各種套件工具時,確實給我們帶來了驚喜,也帶來了新的響亮的名字ajax(Asynchronous JavaScript and XML)。
第一步,我們要回顧“無刷新訪問服務器”技術。
第二步,在源碼中找到dwr中“無刷新訪問服務器”技術的原始代碼。
第三步,我們再簡單的總結總結。
1)“無刷新訪問服務器”技術
var xmlhttp=null;
function PostOrder(xmldoc)


{
var xmlhttp = new ActiveXObject("Msxml2.XMLHTTP.5.0");
xmlhttp.Open("POST", "http://myserver/orders/processorder.asp";, false); //設置XMLHTTP對象,這個對象可以執行向預定目標地址以Post方式發送數據包。
//http://myserver/orders/processorder.asp服務器端專門用來接收數據的地址
xmlhttp.onreadystatechange= HandleStateChange;//設置客戶端響應狀態,發送數據后,服務器會響應
xmlhttp.Send(xmldoc);//發送數據,xmldoc是xml結構化的數據
myButton.disabled = true;
}
function HandleStateChange()


{
if (xmlhttp.readyState == 4)//當收到正確響應時狀態變成4,否則一直等待

{
myButton.disabled = false;
alert("Result = " + xmlhttp.responseXML.xml);//返回的數據
}
}

var xmlDoc=new ActiveXObject("MSXML2.DOMDocument");
flag=xmlDoc.loadXML("");

newNode =xmlDoc.createElement("編碼")
MarkNode=xmlDoc.documentElement.appendChild(newNode);
newNode =xmlDoc.createElement("StartMark")
newNode.text=StartMark;
MarkNode.appendChild(newNode)
newNode =xmlDoc.createElement("EndMark")
newNode.text=EndMark;
MarkNode.appendChild(newNode)
newNode =xmlDoc.createElement("日期")
DateNode=xmlDoc.documentElement.appendChild(newNode);
newNode =xmlDoc.createElement("StartDate");
newNode.text=StartDate;
DateNode.appendChild(newNode)
newNode =xmlDoc.createElement("EndDate")
newNode.text=EndDate;
DateNode.appendChild(newNode);

上面的代碼很好理解吧。好了,這里要給出補充了,實際上ActiveXObject是IE支持的類型,假如瀏覽器不支持這個呢
摘錄了一段比較細的解釋:
1:先建立XMLHttpRequest,建立成功以后要在它的后面緊跟著建立一個xhr.overrideMimeType("text/xml")對于該句的解釋在天極網找到了這么一段話“如果服務器的響應沒有XML mime-type header,某些Mozilla瀏覽器可能無法正常工作。為了解決這個問題,如果服務器響應的header不是text/xml,可以調用其它方法修改該header”。

if(window.XMLHttpRequest)
{
xhr = new XMLHttpRequest();
if(xhr.overrideMimeType)

{ xhr.overrideMimeType("text/xml") ;}
}
2:如果XMLHttpRequest建立不成功就要建立針對IE的ActiveXObject.不同的IE版本有不同ActiveXObject,但是我們現在只要建立兩個就可以了,163是這樣做的于是我也就理解為這樣就可以兼容所有的IE了,具體沒測試過.

try
{
xhr = new ActiveXObject("Msxml.XMLHTTP");

}catch(e)
{

try
{
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}

catch(e)
{}
}兩個try嵌套把兩種情況都寫出來了.

到現在為止,算是回顧了無狀態刷新技術。
2)dwr中“無刷新訪問服務器”技術的原始代碼
在dwr.jar包里,可以找到文件\org\directwebremoting\engine.js,有如下的代碼片段,在這段代碼中,我們能夠找到“無刷新訪問服務器”技術的原始代碼,關注這段代碼中的“看這里”,代碼相對于上面,膨脹了很多呢,主要是處理意外、特殊情況的代碼,沒必要仔細研究。

/**//**
* Remoting through XHR
*/

xhr:
{

/**//**
* The default HTTP method to use
*/
httpMethod:"POST",


/**//**
* The ActiveX objects to use when we want to do an XMLHttpRequest call.
* TODO: We arrived at this by trial and error. Other toolkits use
* different strings, maybe there is an officially correct version?
*/
XMLHTTP:["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"],


/**//**
* Setup a batch for transfer through XHR
* @param {Object} batch The batch to alter for XHR transmit
*/

send:function(batch)
{

if (batch.isPoll)
{
batch.map.partialResponse = dwr.engine._partialResponseYes;
}

// Do proxies or IE force us to use early closing mode?

if (batch.isPoll && dwr.engine._pollWithXhr == "true")
{
batch.map.partialResponse = dwr.engine._partialResponseNo;
}

if (batch.isPoll && dwr.engine.isIE)
{
batch.map.partialResponse = dwr.engine._partialResponseNo;
}
//看這里

if (window.XMLHttpRequest)
{
batch.req = new XMLHttpRequest();
}

else if (window.ActiveXObject)
{
batch.req = dwr.engine.util.newActiveXObject(dwr.engine.transport.xhr.XMLHTTP);
}
//看這里

// Proceed using XMLHttpRequest

if (batch.async)
{

batch.req.onreadystatechange = function()
{

if (typeof dwr != 'undefined')
{
dwr.engine.transport.xhr.stateChange(batch);
}
};
}

// If we're polling, record this for monitoring

if (batch.isPoll)
{
dwr.engine._pollReq = batch.req;
// In IE XHR is an ActiveX control so you can't augment it like this
if (!document.all) batch.req.batch = batch;
}

httpMethod = dwr.engine.transport.xhr.httpMethod;

// Workaround for Safari 1.x POST bug
var indexSafari = navigator.userAgent.indexOf("Safari/");

if (indexSafari >= 0)
{
var version = navigator.userAgent.substring(indexSafari + 7);

if (parseInt(version, 10) < 400)
{

if (dwr.engine._allowGetForSafariButMakeForgeryEasier == "true")
{
httpMethod = "GET";
}

else
{

dwr.engine._handleWarning(batch,
{
name: "dwr.engine.oldSafari",
message: "Safari GET support disabled. See getahead.org/dwr/server/servlet and allowGetForSafariButMakeForgeryEasier."
});
}
}
}

batch.mode = batch.isPoll ? dwr.engine._ModePlainPoll : dwr.engine._ModePlainCall;
var request = dwr.engine.batch.constructRequest(batch, httpMethod);


try
{
batch.req.open(httpMethod, request.url, batch.async);//看這里,發送設置

try
{

for (var prop in batch.headers)
{
var value = batch.headers[prop];

if (typeof value == "string")
{
batch.req.setRequestHeader(prop, value);
}
}

if (!batch.headers["Content-Type"])
{
batch.req.setRequestHeader("Content-Type", "text/plain");
}
}

catch (ex)
{
dwr.engine._handleWarning(batch, ex);
}
batch.req.send(request.body);//看這里,執行發送

if (!batch.async)
{
dwr.engine.transport.xhr.stateChange(batch);
}
}

catch (ex)
{
dwr.engine._handleError(batch, ex);
}


if (batch.isPoll && batch.map.partialResponse == dwr.engine._partialResponseYes)
{
dwr.engine.transport.xhr.checkCometPoll();
}

// This is only of any use in sync mode to return the reply data
return batch.reply;
},
3)在batch.req.send(request.body)代碼行上添加alert("see me:"+request.body);可以看到執行發送時,到底發送了什么。
1,在我進入dwr工程的首頁時。alert彈出的內容如下:
see me:callCount=1
windowName=DWR-4B6B




.06
c0-scriptName=_System
c0-methodName=pageLoaded
c0-id=0
batchId=0
page=/dwr/
httpSessionId-
scriptSessionId=
2,在我們進入樣例Dynamically Text中,點擊發送時,alert彈出內容
see me:callCount=1
windowName=DWR-4B6B
.2D06
c0-scriptName=Demo
c0-methodName=sayHello
c0-id=0
c0-param0=string:Joe
batchId=1
page=/dwr/simpletext/index.html
httpSessionId=
scriptSessionId=A822
701A
3,當我進入樣例Edit Table時,刪除表中一行時,alert彈出內容
see me:callCount=2
windowName=DWR-4B6B
.D06
c0-scriptName=People
c0-methodName=deletePerson
c0-id=0
c0-e1=number:18

c0-param0=Object_Object:
{id:reference:c0-e1}
c1-scriptName=People
c1-methodName=getAllpeople
c1-id=1
batchId=2
page=/dwr/people/index.html
httpSessionId=
scriptSessionId=2557C
..42A1
看看上面這些,比較比較不同處,現在可能還不好理解,當我們在后面講解dwr原理時,回過頭來看會更能理解。
我們先提前解釋一下:
callCount=1 表示執行了多少個方法
c0-scriptName =Demo 調用了那個java類 c后面的序號是方法的序號,如果有兩個方法,那么就有c0,c1,見第三個例子
c0-methodName=sayHello 調用了類中的哪個方法
c0-id =0 方法序號
c0-param1=String: Joe 傳遞的值,這個值對應于java方法的參數
page=/dwr/.. 路徑
總結:
dwr通過無狀態刷新技術,向服務器端發送數據包,服務器端響應,客戶端收到返回數據后,作出變化。
下面這一段話是更詳細的技術細節
【
以樣例Dynamically Text為例
在瀏覽器加載http://localhost:5050/dwr/simpletext/index.html時,
瀏覽器遇到下面這句話
<script type='text/javascript' src='../dwr/interface/Demo.js'> </script>
就執行dwrServlet.java(web.xml有dwr相關配置),向服務器調用發送類似于樣例1的內容,不執行任何操作。
當我們真正點擊發送按鈕時,向服務器發送樣例2的數據,告訴服務器,我會調用哪個類的哪個方法,并且傳什么樣的參數,參數內容是什么。
不用說,服務器端肯定是接收相應的數據,激發相應的類相應的方法
對于參數,涉及到字符串數據比如String:Joe,轉換為java對象,有專門的轉換類處理,后綴為convert的類
】