从2005年开始,ajax在全球渐渐掀起了一股潮流,它使浏览器可以为用户提供更为自然的浏览体验,全球几百个ajax项目中,dwr就是其中一项。
     ajax采用的技术基石其实早就有了,就是“无刷新访问服务器”技术,所以有人说ajax其实就是新瓶装老酒,一点没错,就是新瓶装老酒,在工程师们将“无刷新访问服务器”技术封装成各种套件工具时,确实给我们带来了惊喜,也带来了新的响亮的名字ajax(Asynchronous JavaScript and XML)。
第一步,我们要回顾“无刷新访问服务器”技术。
第二步,在源码中找到dwr中“无刷新访问服务器”技术的原始代码。
第三步,我们再简单的总结总结。
      1)“无刷新访问服务器”技术
 var xmlhttp=null;
var xmlhttp=null;
 function PostOrder(xmldoc)
function PostOrder(xmldoc)


 {
{
 var xmlhttp = new ActiveXObject("Msxml2.XMLHTTP.5.0");
  var xmlhttp = new ActiveXObject("Msxml2.XMLHTTP.5.0");
 xmlhttp.Open("POST", "http://myserver/orders/processorder.asp";, false); //设置XMLHTTP对象,这个对象可以执行向预定目标地址以Post方式发送数据包。
  xmlhttp.Open("POST", "http://myserver/orders/processorder.asp";, false); //设置XMLHTTP对象,这个对象可以执行向预定目标地址以Post方式发送数据包。
 //http://myserver/orders/processorder.asp服务器端专门用来接收数据的地址
//http://myserver/orders/processorder.asp服务器端专门用来接收数据的地址
 xmlhttp.onreadystatechange= HandleStateChange;//设置客户端响应状态,发送数据后,服务器会响应
  xmlhttp.onreadystatechange= HandleStateChange;//设置客户端响应状态,发送数据后,服务器会响应
 xmlhttp.Send(xmldoc);//发送数据,xmldoc是xml结构化的数据
  xmlhttp.Send(xmldoc);//发送数据,xmldoc是xml结构化的数据
 myButton.disabled = true;
  myButton.disabled = true;
 }
}
 function HandleStateChange()
function HandleStateChange()


 {
{
 if (xmlhttp.readyState == 4)//当收到正确响应时状态变成4,否则一直等待
  if (xmlhttp.readyState == 4)//当收到正确响应时状态变成4,否则一直等待

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

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

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

    上面的代码很好理解吧。好了,这里要给出补充了,实际上ActiveXObject是IE支持的类型,假如浏览器不支持这个呢
摘录了一段比较细的解释:
 1:先建立XMLHttpRequest,建立成功以后要在它的后面紧跟着建立一个xhr.overrideMimeType("text/xml")对于该句的解释在天极网找到了这么一段话“如果服务器的响应没有XML mime-type header,某些Mozilla浏览器可能无法正常工作。为了解决这个问题,如果服务器响应的header不是text/xml,可以调用其它方法修改该header”。
1:先建立XMLHttpRequest,建立成功以后要在它的后面紧跟着建立一个xhr.overrideMimeType("text/xml")对于该句的解释在天极网找到了这么一段话“如果服务器的响应没有XML mime-type header,某些Mozilla浏览器可能无法正常工作。为了解决这个问题,如果服务器响应的header不是text/xml,可以调用其它方法修改该header”。

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

 
       { xhr.overrideMimeType("text/xml") ;}
{ xhr.overrideMimeType("text/xml") ;}
 }
}
 2:如果XMLHttpRequest建立不成功就要建立针对IE的ActiveXObject.不同的IE版本有不同ActiveXObject,但是我们现在只要建立两个就可以了,163是这样做的于是我也就理解为这样就可以兼容所有的IE了,具体没测试过.
2:如果XMLHttpRequest建立不成功就要建立针对IE的ActiveXObject.不同的IE版本有不同ActiveXObject,但是我们现在只要建立两个就可以了,163是这样做的于是我也就理解为这样就可以兼容所有的IE了,具体没测试过.

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

 }catch(e)
    }catch(e) {
{

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

 catch(e)
    catch(e) {}
{}
 }两个try嵌套把两种情况都写出来了.
  }两个try嵌套把两种情况都写出来了.

     到现在为止,算是回顾了无状态刷新技术。
     2)dwr中“无刷新访问服务器”技术的原始代码
     在dwr.jar包里,可以找到文件\org\directwebremoting\engine.js,有如下的代码片段,在这段代码中,我们能够找到“无刷新访问服务器”技术的原始代码,关注这段代码中的“看这里”,代码相对于上面,膨胀了很多呢,主要是处理意外、特殊情况的代码,没必要仔细研究。

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

 xhr:
    xhr: {
{

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


 /**//**
      /**//**
 * The ActiveX objects to use when we want to do an XMLHttpRequest call.
       * 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
       * TODO: We arrived at this by trial and error. Other toolkits use
 * different strings, maybe there is an officially correct version?
       * 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"],
      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
       * Setup a batch for transfer through XHR
 * @param {Object} batch The batch to alter for XHR transmit
       * @param {Object} batch The batch to alter for XHR transmit
 */
       */

 send:function(batch)
      send:function(batch)  {
{

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

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

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

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

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

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

 // Proceed using XMLHttpRequest
        // Proceed using XMLHttpRequest

 if (batch.async)
        if (batch.async)  {
{

 batch.req.onreadystatechange = function()
          batch.req.onreadystatechange = function()  {
{

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

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

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

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

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

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

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

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

 else
            else  {
{

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

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


 try
        try  {
{
 batch.req.open(httpMethod, request.url, batch.async);//看这里,发送设置
          batch.req.open(httpMethod, request.url, batch.async);//看这里,发送设置

 try
          try  {
{

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

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

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

 catch (ex)
          catch (ex)  {
{
 dwr.engine._handleWarning(batch, ex);
            dwr.engine._handleWarning(batch, ex);
 }
          }
 batch.req.send(request.body);//看这里,执行发送
          batch.req.send(request.body);//看这里,执行发送

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

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


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

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




 .06
.06
 c0-scriptName=_System
c0-scriptName=_System
 c0-methodName=pageLoaded
c0-methodName=pageLoaded
 c0-id=0
c0-id=0
 batchId=0
batchId=0
 page=/dwr/
page=/dwr/
 httpSessionId-
httpSessionId-
 scriptSessionId=
scriptSessionId=
    2,在我们进入样例Dynamically Text中,点击发送时,alert弹出内容
 see me:callCount=1
see me:callCount=1
 windowName=DWR-4B6B
windowName=DWR-4B6B .2D06
.2D06
 c0-scriptName=Demo
c0-scriptName=Demo
 c0-methodName=sayHello
c0-methodName=sayHello
 c0-id=0
c0-id=0
 c0-param0=string:Joe
c0-param0=string:Joe
 batchId=1
batchId=1
 page=/dwr/simpletext/index.html
page=/dwr/simpletext/index.html
 httpSessionId=
httpSessionId=
 scriptSessionId=A822
scriptSessionId=A822 701A
701A    3,当我进入样例Edit Table时,删除表中一行时,alert弹出内容
 see me:callCount=2
see me:callCount=2
 windowName=DWR-4B6B
windowName=DWR-4B6B
 .D06
.D06
 c0-scriptName=People
c0-scriptName=People
 c0-methodName=deletePerson
c0-methodName=deletePerson
 c0-id=0
c0-id=0
 c0-e1=number:18
c0-e1=number:18

 c0-param0=Object_Object:
c0-param0=Object_Object: {id:reference:c0-e1}
{id:reference:c0-e1}
 c1-scriptName=People
c1-scriptName=People
 c1-methodName=getAllpeople
c1-methodName=getAllpeople
 c1-id=1
c1-id=1
 batchId=2
batchId=2
 page=/dwr/people/index.html
page=/dwr/people/index.html
 httpSessionId=
httpSessionId=
 scriptSessionId=2557C
scriptSessionId=2557C ..42A1
..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的类
      】