`
huajiangan
  • 浏览: 5199 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

ajaxanywhere教程

 
阅读更多

AjaxAnywhere简介

 

来源:http://blog.csdn.net/flyfish778/article/details/5709903

 

AjaxAnywhere的官方站点是http://ajaxanywhere.sourceforge.net,本书撰写的时候最新的版本是1.1.0.6,读者可以从sourceforge.net下载到最新的jar开发包、src源码包,以及一个demo演示包。本书使用AjaxAnywhere1.1.0.6版本。

AjaxAnywhere使用“分区刷新”的思路,其工作原理如下。

1)使用AjaxAnywhere自定义标签库将一个Web页面划分为几个可重载的区域(reload-capable zones)。

2)使用AjaxAnywhere Javascript 应用编程接口(API)替代传统通信机制下表单提交方式。

3)当请求在服务器端处理的时候,决定那些页面区域可以刷新(refresh)。这个过程可以使用基于客户端的Javascript或者基于服务器端的AjaxAnywhere应用编程接口(API)。

4)在服务器端,AjaxAnywhere会生成包含即将更新的HTML代码的XML文档。

5)在客户端,AjaxAnywhere Javascript接受这个XML文档,解析文档,并更新指定的页面区域。

采取这样的设计思路,可以尽可能地降低Javascript代码量,降低Ajax的开发门槛。

无须掌握和开发那么多的Javascript代码。

由于缺乏被广泛接受的命名习惯、格式化规则和模式,使得Javascript编码相对Java/JSP复杂许多,尤其在浏览器兼容性方面缺乏有效的调试和单元测试手段。使用AjaxAnywhere可以摆脱这些Javascript的复杂性。

方便集成。

使用AjaxAnywhere无须改变底层的应用程序代码。

降低技术风险。

可以随时在传统的通信机制和Ajax之间切换,允许Web应用程序同时支持两种通信机制。

平滑的兼容性。

再也不用在使用Ajax还是传统的交互方式间摇摆了,使用Ajax AnyWhereWeb应用程序可以兼容两种请求方式。

AjaxAnywhere的客户端脚本经过了IEMozilla FirefoxOpera等浏览器的兼容性测试,能够最大程度地保证代码的浏览器兼容性。

另外,还需要注意的AjaxAnywhere特性是,Ajax接收到的Ajax代码采用特殊的方式处理。AjaxAnywhere通过eval("")的方式执行这些Javascript代码,也可以将所定义的Javascript函数保存在适当的上下文(Context)中。不过,在允许Ajax方式重载的页面区域,不允许执行document.write()之类的Javascript语句。

允许重载的区域可能在提交请求之前就确定了,这种情况下需要重载客户端的AjaxAnywhere.getZonesToReload()Javascript函数,不需要额外的服务器逻辑处理。

如果希望AjaxAnywhere重载整个文档,则重载后的AjaxAnywhere.getZonesToReload()函数必须返回“document.all”字符串,也可以在服务器端调用AAUtils.setRefreshAll(true)刷新整个页面。

相应的,Ajax请求中的response.sendRedirect()会被转化成Javascript代码的location.replace()命令。

 

 

Ajax Anywhere安装

 

如果要将AjaxAnywhere集成到自己的Web应用程序中,可以通过以下5个步骤来完成简单的配置。

第一步:下载最新的AjaxAnywhere开发包或者二进制分发版本。

AjaxAnywhere官方网站下载最新的开发包,包括jar--ajaxanywhere-1.1.0.6.jarjs--aa.js文件等。

第二步:获取必要的Javascript文件。

从下载的开发包中获取Javascript文件aa.js,放到Web应用程序根目录中。

第三步:将下载下来的jar包复制到/WEB-INF/lib目录中。

第四步:修改web.xml,添加AAFilter过滤器。

修改部署描述文件web.xml,在该文件中添加AAFilter过滤器。映射部分的部署代码如例程11-22所示。

例程11-22  web.xml添加AAFilter过滤器

    <filter>

        <filter-name>AjaxAnywhere</filter-name>

        <filter-class>org.ajaxanywhere.AAFilter</filter-class>

    </filter>

    <filter-mapping>

        <filter-name>AjaxAnywhere</filter-name>

        <url-pattern>*.jsp</url-pattern>

    </filter-mapping>

    <filter-mapping>

        <filter-name>AjaxAnywhere</filter-name>

        <url-pattern>*.do</url-pattern> <!-- default Struts mapping -->

    </filter-mapping>

    <filter-mapping>

        <filter-name>AjaxAnywhere</filter-name>

        <url-pattern>*.htm</url-pattern> <!-- other framewords mapping -->

</filter-mapping>

例程11-22Web应用程序中的URL以后缀.jspdohtm结尾的请求全部有过滤器AAFilter过滤。而在实际项目中,可以根据项目实际需求来修改url-pattern的值,定制要应用AjaxAnywhere的请求类型,即只有特定的请求才应用AjaxAnywhere处理。

 

 

AjaxAnywhere的类库及其用法

 

jaxAnywhere使用一个名为aa.jsJavascript文件来处理客户端的全部Ajax操作,包括初始化XMLHttpRequest、获取表单内容、发送Ajax请求、执行回调函数等。aa.js也是使AjaxAnywhere之前必须了解的,至少应该知道其经常用到的APIAjax Anywhere的官方网站提供了相应的Javascript Document,方便快速查找和了解这些API

1AjaxAnywhere的初始化

aa.js中定义了一个AjaxAnywhere对象,针对Ajax的各种操作被抽象成AjaxAnywhere对象的方法,通过这些对象方法完成所需的操作。必要的时候,可以重载这些方法,以便满足个性化的需求。在aa.js文件的末端,AjaxAnywhere对象使用默认的构造方法完成对象实例化。

ajaxAnywhere = new AjaxAnywhere();

ajaxAnywhere.bindById();

所以,所有引用aa.js的页面都可以在Javascript代码段中使用AjaxAnywhere对象的实例ajaxAnywhere

AjaxAnywhere初始化的时候,它在默认的构造函数中完成XMLHttpRequest对象的创建,并保存在AjaxAnywhere对象属性req中。AjaxAnywhere对象默认的构造方法如例程11-23所示。

例程11-23  AjaxAnywhere对象的默认构造方法

function AjaxAnywhere() {

    this.id = AjaxAnywhere.defaultInstanceName;//id,用于生成更新区域的编号等用途

    this.formName = null;//页面表单名称

    this.notSupported = false;//是否支持Ajax

    this.delayBeforeContentUpdate = true;//在更新页面内容之前是否延迟

    this.delayInMillis = 100;//延迟时间

    //初始化XMLHttpRequest对象--req

    if (window.XMLHttpRequest) {

        this.req = new XMLHttpRequest();

    } else if (window.ActiveXObject) {

        try {

            this.req = new ActiveXObject("Msxml2.XMLHTTP");

        } catch(e) {

            try {

                this.req = new ActiveXObject("Microsoft.XMLHTTP");

            } catch(e1) {

                this.notSupported = true;

                /* XMLHTTPRequest not supported */

            }

        }

    }

    //确定浏览器是否支持Ajax

    if (this.req == null || typeof this.req == "undefined")

        this.notSupported = true;

}

2AjaxAnywhere处理Ajax请求

AjaxAnywhere提供两个公共方法处理Ajax请求的发送:submitAJAX(additionalPost Data, submitButton)getAJAX(url, zonesToRefresh)。前者用于发送POST类型的Ajax请求,后者则用于发送GET类型的请求,可以直接在Web页面的表单中或者Javascript代码段直接使用ajaxAnywhere.submitAJAX(additionalPostData, submitButton)或者ajaxAny where. getAJAX (url, zonesToRefresh)向服务器发送Ajax请求。

ajaxAnywhere对象的属性formName保存Ajax所指向的表单名称,只要为其指定表单名称(如果未指定,则默认是Web页面中的第一个表单),submitAJAX(additionalPost Data,submitButton)就能够自动获取指定表单的全部表单域及其值,组成parameterName1 =value1 &parameterName2=value2字符串,这个过程由私有(private)方法preparePostData (submitButton)完成;preparePostData(submitButton)方法遍历表单中的全部元素,将下拉列表、文本框、复选框、单选框等的值自动加入字符串中;submitAJAX方法的参数additionalPostData代表除了表单域值外还要发送给服务器的内容,submitButton则是代表发送操作是否由提交按钮触发的。SubmitAJAX()方法的代码如例程11-24所示。

例程11-24  submitAJAX() 方法发送POST类型请求

AjaxAnywhere.prototype.submitAJAX = function(additionalPostData, submitButton) {

    //如果浏览器不支持Ajax

    if (this.notSupported)

        return this.onSubmitAjaxNotSupported(additionalPostData);

    //附加参数为空

    if (additionalPostData == null || typeof additionalPostData == "undefined")

        additionalPostData = "";

    //id绑定

    this.bindById();

    //获取当前表单对象

    var form = this.findForm();

    //获取表单的action,确定表单提交目标的url

    var actionAttrNode = form.attributes.getNamedItem("action");

    var url = actionAttrNode == null?null:actionAttrNode.nodeValue;

    //如果表单action未设置,则url为当前页面

    if ((url == null) || (url == ""))

        url = location.href;

    //确定请求成功后要重载刷新的页面区域

    var zones = this.getZonesToReload(url, submitButton);

    //如果未设置重载刷新区域,则刷新整个页面

    if (zones == null) {

        if (typeof form.submit_old == "undefined")

            form.submit();

        else

            form.submit_old();

        return;

    }

    //放弃上一次未完成的请求

    this.dropPreviousRequest();

    //设置请求参数,发送类型为POST,请求为异步方式

    this.req.open("POST", url, true);

    this.req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

    this.req.setRequestHeader("Accept", "text/xml");

    //确定要发送给服务器的内容

    var postData = this.preparePostData(submitButton);

    //已设置要重载刷新的区域,将区域名称附加在发送内容中

    if (zones != "")

        postData = '&aazones=' + encodeURIComponent(zones) + "&" + postData + "&" + additionalPostData;

    else

        postData += "&" + additionalPostData;

    //发送Ajax请求

    this.sendPreparedRequest(postData);

}

显然,如果使用AjaxAnywhere自定义标签为Web页面划分指定了刷新区域,则submitAJAX()方法也会将其包含在参数中发送到服务器端。

相对的,getAJAX(url,zoneToRefresh)方法则比较简单。它获取Ajax请求的目标URL,将需要发送的参数附着在这个URL后面,然后调用XMLHttpRequest对象的open()send()方法将其发送除去。getAJAX(url,zoneToRefresh)方法的代码如例程11-25所示。

例程11-25  getAJAX()方法发送GET类型请求

AjaxAnywhere.prototype.getAJAX = function(url, zonesToRefresh) {

    //如果浏览器不支持Ajax,则刷新整个页面

    if (this.notSupported)

        return this.onGetAjaxNotSupported(url);

    //id绑定

    this.bindById();

    //如果为设置刷新区域,则刷新整个页面

    if (zonesToRefresh == null || typeof zonesToRefresh == "undefined")

        zonesToRefresh = "";

    var urlDependentZones = this.getZonesToReload(url);

    if (urlDependentZones == null) {

        location.href = url;

        return;

    }

    //已经设置多个刷新区域

    if (urlDependentZones.length != 0)

        zonesToRefresh += "," + urlDependentZones;

    //放弃上一次未完成的额请求

    this.dropPreviousRequest();

    //确定请求附加的参数

    url += (url.indexOf("?") != -1) ? "&" : "?";

 

    url += "aa_rand=" + Math.random();

    // avoid caching

 

    if (zonesToRefresh != null && zonesToRefresh != "")

        url += '&aazones=' + encodeURIComponent(zonesToRefresh);

    //设置请求参数,发送类型为GET,响应结果为XML文档

    this.req.open("GET", url, true);

    this.req.setRequestHeader("Accept", "text/xml");

    //发送Ajax请求

    this.sendPreparedRequest("");

}

与一般的Ajax应用程序一样,AjaxAnywhere更新页面的操作仍然由回调函数完成,这也是Ajax的机制所定义的。应该注意到,submitAJAX()方法和getAJAX()方法的后面都调用了一个sendPreparedRequest()的方法,只是两者传入的参数内容有所不同而已。AjaxAnywhere对象在该方法中设置必要的请求头信息,为XMLHttpRequest对象指定回调函数,然后才将Ajax请求发送出去。setPreparedRequest()方法如例程11-26所示。

例程11-26  setPreparedRequest()方法

AjaxAnywhere.prototype.sendPreparedRequest = function (postData) {

    //确定Ajax请求回调函数

    var callbackKey = this.id + "_callbackFunction";

    if (typeof window[callbackKey] == "undefined")

        window[callbackKey] = new Function("AjaxAnywhere.findInstance (/"" + this.id + "/").callback(); ");

    this.req.onreadystatechange = window[callbackKey];

    //显示请求正在处理的提示信息

    this.showLoadingMessage();

    //设置请求头参数,当前请求为aaxml请求

    this.req.setRequestHeader("aaxmlrequest", "true");

    //发送请求

    this.req.send(postData);

}

从这个方法可以看出,如果未在Web页面中定义相应的回调函数,则AjaxAnywhere将使用默认的回调函数。

AjaxAnywhere统一使用XML文档来组织服务器返回的响应数据。这个文档采用UTF-8的编码方式,例程11-22所配置的AAFilter也采用UTF-8的方式从请求中获取请求数据。AjaxAnywhere支持页面区域内容刷新、URL跳转、脚本、图像等处理功能,这些处理功能的信息都包含在这个XML文档中。当客户端发送的Ajax请求被正常执行后,AjaxAnywhere即将返回的响应数据组织为符合例程11-27所示文档类型定义文件DTD所规定范式的XML文档。

例程11-27  AjaxAnywhere返回的XML文档的文档类型定义DTD

<?xml version="1.0" encoding="UTF-8" ?>

<!ELEMENT zones ( document*, zone*, script*, exception*, redirect*, image* ) >

<!ELEMENT document (#PCDATA)>

<!ELEMENT zone ( #PCDATA ) >

<!ATTLIST zone name NMTOKEN #REQUIRED >

<!ELEMENT script ( #PCDATA ) >

<!ELEMENT exception ( #PCDATA ) >

<!ATTLIST exception type NMTOKEN #REQUIRED >

<!ELEMENT redirect ( #PCDATA ) >

<!ELEMENT image (#PCDATA) >

例程11-28是一个仅包含zonescriptexceptionredirect节点的示范XML文档。这个文档由AjaxAnywhere的业务类自动组织,与Web应用程序的其他实体类、业务类无关。Web应用程序只需要按照传统的通信机制一样,将响应结果输出即可。

例程11-28  AjaxAnywhere返回的包含响应数据的XML文档

<?xml version="1.0" encoding="UTF-8"?>

<zones>

    <zone name="stateSavingScript"/>

    <zone name="countriesList">

        <![CDATA[

            <select size="10" name="country">

                <option value=IN>India</options>

            </select>

        ]]>

    </zone>

    <script>

        <![CDATA[

            var states = document.getElementsByName("jsf_state_64")

            var trees = document.getElementsByName("jsf_tree_64")

            if(states!=null)

                for(var i=0;i<states.length;i++)

                    if(states[i].tagName.toLowerCase()=="input") {

                        states[i].values="null";

                    }

            if(trees!=null)

                for(var i=0;i<trees.length;i++)

                    if(trees[i].tagName.toLowerCase()=="input")

                        trees[i].values="null";

        ]]>

    </script>

    <script/>

    <script/>

    <exception type="org.apache.jasper.JasperException"><![CDATA[

    org.apache.jasper.JasperException:AjaxAnywhere demo exception

        at org.apache.jasper.servlet.JspServletWraper.service (Jsp Servlet Wrapper.java:372)

        ............

    ]]>

    </exception>

    <redirect><![CDATA[reditected.jsp]]></redirect>

</zones>

AjaxAnywhere默认的回调函数使用XMLHttpRequest对象的responseXML()方法来获取服务器返回的这个XML文档,使用DOM解析。如果XML文档包含documentzone元素,则按照之前设定的更新区域来更新页面中指定区域的内容。如果XML文档中包含script元素,则从元素中提取脚本,使用eval()方法执行。如果服务器响应请求的时候发生系统异常或者HTTP请求异常,则XML文档中会包含exception元素,回调函数即可从元素中获取异常信息,交给this.handleException (type, details)方法做异常处理。如果XML文档中包含redirect元素,则回调函数将其转化为“locarion.href=newURL”的方法,将页面跳转到指定的URL。如果XML文档中包含image元素,则AjaxAnywhere即从服务器获取image对象所指定的图像,将其缓存在浏览器。AjaxAnywhere默认的回调函数如例程11-29所示。

例程11-29  AjaxAnywhere对象默认的构造函数

AjaxAnywhere.prototype.callback = function() {

 

    if (this.req.readyState == 4) {

 

        this.onBeforeResponseProcessing();

        this.hideLoadingMessage();

 

        if (this.req.status == 200) {

           if (this.req.getResponseHeader('content-type').toLowerCase(). substring(0, 8) != 'text/xml')

                alert("AjaxAnywhere error : content-type in not text/xml : [" + this.req.getResponseHeader('content-type') + "]");

 

            var docs = this.req.responseXML.getElementsByTagName("documen t");

          var redirects = this.req.responseXML.getElementsByTagNa me ("redirect");

            var zones = this.req.responseXML.getElementsByTagName("zon e");

            var exceptions = this.req.responseXML.getElementsByTagName ("exception");

            var scripts = this.req.responseXML.getElementsByTagName("scr ipt");

            var images = this.req.responseXML.getElementsByTagName("imag e");

 

            if (redirects.length != 0) {

                var newURL = redirects[0].firstChild.data;

                location.href = newURL;

            }

            if (docs.length != 0) {

                var newContent = docs[0].firstChild.data;

 

                //cleanup ressources

                delete this.req;

 

                document.close();

                document.write(newContent);

                document.close();

            }

 

            if (images.length != 0) {

                var preLoad = new Array(images.length);

                for (var i = 0; i < images.length; i++) {

                    var img = images[i].firstChild;

                    if (img != null) {

                        preLoad[i] = new Image();

                        preLoad[i].src = img.data;

                    }

                }

                if (this.delayBeforeContentUpdate) {

                    delay(this.delayInMillis);

                }

            }

 

            if (zones.length != 0) {

                for (var i = 0; i < zones.length; i++) {

                    var zoneNode = zones[i];

                    var name = zoneNode.getAttribute("name");

                    var fc = zoneNode.firstChild;

 

                    var html = (fc == null)?"":fc.data;

 

                    var zoneHolder = document.getElementById("aazone." + name);

                    if (zoneHolder != null && typeof(zoneHolder) != "undefined") {

                        zoneHolder.innerHTML = html;

                    }

 

                }

            }

            if (exceptions.length != 0) {

                var e = exceptions[0];

                var type = e.getAttribute("type");

                var stackTrace = e.firstChild.data;

                this.handleException(type, stackTrace);

            }

 

            if (scripts.length != 0) {

                for (var $$$$i = 0; $$$$i < scripts.length; $$$$i++) {

                    // use $$$$i variable to avoid collision with "i" inside user script

                    var script = scripts[$$$$i].firstChild;

                    if (script != null) {

                        script = script.data;

                        if (script.indexOf("document.write") != -1) {

                            this.handleException("document.write", "This script contains document.write(), which is not compatible with AjaxAnywhere : /n/n" + script);

                        } else {

                            eval(script);

                        }

                    }

                }

 

                var globals = this.getGlobalScriptsDeclarationsList(scr ipt);

                if (globals != null)

                    for (var i in globals) {

                        var objName = globals[i];

                        try {

                            window[objName] = eval(objName);

                        } catch(e) {

                        }

                    }

            }

 

        } else {

            if (this.req.status != 0)

                this.handleHttpErrorCode(this.req.status);

        }

        this.restoreSubstitutedSubmitButtons();

        this.onAfterResponseProcessing();

    }

}

值得注意的是,在例程11-29所示的默认回调函数中,除了解析XML文档外,在回调函数执行业务逻辑之前和之后,还分别调用了两个可供重载的方法:this.onBeforeResp onse Processing() this.onAfterResponseProcessing()。如果希望在执行回调函数更新页面内容之前处理额外的业务,则可以在适当的位置重载this.onBeforeResponseProcessing()方法。如果希望执行完回调函数更新页面内容之后,还希望继续执行其他逻辑操作,则可以在适当的位置重载this.onAfterResponseProcessing()方法。从aa.js的源码中,可以看到目前这两个方法都未执行任何操作,如例程11-30所示。

例程11-30  onBeforeResponseProcessing()onAfterResponseProcessing()方法

/**

* Override this method to implement a custom action

*/

AjaxAnywhere.prototype.onBeforeResponseProcessing = function () {

};

/**

* Override this method to implement a custom action

*/

AjaxAnywhere.prototype.onAfterResponseProcessing = function () {

};

 

 

 

3AjaxAnywhere处理系统异常和HTTP请求异常

Web应用程序中,系统异常和HTTP请求异常的处理一向是件比较头疼的事情。在Ajax应用程序中,这两个异常的处理会比传统的通信机制下相对棘手,惟一比较有效的方式就是在回调函数中判断HTTP请求的状态码并做相应的处理。如果异常未加以处理,用户根本不知道请求到底执行成功没有,页面上也不会有任何的反应,不像传统的通信机制下会显示“HTTP404错误”等类似的错误页面。

比较可喜的是,AjaxAnywhere提供了一种比较方便的异常处理方式。之前提到的,AjaxAnywhere将服务器返回的响应数据包装成一个XML文档,这个XML文档中同样也包含系统异常和HTTP请求异常的信息,它们被封装在exception元素中。在AjaxAnywhere默认的回调函数中可以看到,它将系统异常的信息交由this.handleException (type,detail)方法处理,而HTTP请求异常则交由this. handleHttpErrorCode(code)方法处理。默认的this.handle Exception(type,detail)方法将系统异常的细节显示在弹出窗口中,如图11-22所示,其代码如例程11-31所示。

例程11-31  AjaxAnywhere处理系统异常的方法

AjaxAnywhere.prototype.handleException = function(type, details) {

    alert(details);

}

11-22  AjaxAnywhere显示的系统异常信息

而默认的this.handleHttpErrorCode(code)则允许用户在一个新的页面中显示HTTP请求异常信息,如图11-23所示,其代码如例程11-32所示。

例程11-32  AjaxAnywhere处理HTTP请求异常的方法

AjaxAnywhere.prototype.handleHttpErrorCode = function(code) {

    var details = confirm("AjaxAnywhere default error handler. XMLHttp Request HTTP Error code:" + code + " /n/n Would you like to view the response content in a new window?");

    if (details) {

        var win = window.open("", this.id + "_debug_window");

        if (win != null) {

            win.document.write("<html><body><xmp>" + this.req.response Text);

            win.document.close();

            win.focus();

        } else {

            alert("Please, disable your pop-up blocker for this site fir st.");

        }

    }

}

11-23  AjaxAnywhere显示的HTTP请求异常

如果用户希望系统提供更加人性化的系统异常和HTTP异常处理机制,则可以重载这两个异常处理方法。AjaxAnywheredemo示范包中有相应的案例可供参考,如图11-24和图11-25所示。

11-24  重载后的系统异常处理

11-25  重载后的HTTP请求异常处理

4.定制Ajax请求执行的提示信息

之前说过,在Ajax应用程序中,当Ajax请求正在执行的时候,应当在页面的适当位置提示用户请求正在执行。而Ajax请求执行完毕后,应当提示用户页面已经更新。AjaxAnywhere提供了默认的解决方案,在页面右上角显示一个“Loading…”的蓝色提示条,如图11-26所示,其实质是一个固定位置的DIV浮动层。

11-26  AjaxAnywhere默认的Ajax请求执行提示信息

AjaxAnywhere对象的方法showLoadingMessage()hideLoadingMessage()用于显示和隐藏这个提示信息,它们分别在Ajax请求发送前和回调函数中被调用,其代码如例程11-33所示。

例程11-33  AjaxAnywhere默认的Ajax请求执行提示信息方法

AjaxAnywhere.prototype.showLoadingMessage = function() {

 

    var div = document.getElementById("AA_" + this.id + "_loading_ div");

    if (div == null) {

        div = document.createElement("DIV");

 

        document.body.appendChild(div);

        div.id = "AA_" + this.id + "_loading_div";

 

        div.innerHTML = "&nbsp;Loading...";

        div.style.position = "absolute";

        div.style.border = "1 solid black";

        div.style.color = "white";

        div.style.backgroundColor = "blue";

        div.style.width = "100px";

        div.style.heigth = "50px";

        div.style.fontFamily = "Arial, Helvetica, sans-serif";

        div.style.fontWeight = "bold";

        div.style.fontSize = "11px";

    }

    div.style.top = document.body.scrollTop + "px";

    div.style.left = (document.body.offsetWidth - 100 - (document.all? 20:0)) + "px";

 

    div.style.display = "";

}

 

AjaxAnywhere.prototype.hideLoadingMessage = function() {

    var div = document.getElementById("AA_" + this.id + "_loading_ div");

    if (div != null)

        div.style.display = "none";

}

在必要的时候,可以在页面的适当位置重载上述两个方法,提供个性化的提示信息。例程11-34重载上述两个方法,将这个提示信息替换成轮显的图片,如图11-27所示。读者可以在AjaxAnywheredemo演示包中找到这个案例。

例程11-34  重载后的Ajax请求提示信息方法

ajaxAnywhere.showLoadingMessage = function() {

    var img = document.getElementById("myImg");

    if (img == null) {

        img = document.createElement("img");

        document.body.appendChild(img);

 

        img.id = "myImg";

 

        img.src = "balls.gif";

        img.style.position = "absolute";

        img.style.border = "1 solid black";

        img.style.top = 0;

        img.style.left = document.body.offsetWidth - 170;

    }

    img.style.display = "";

}

 

AjaxAnywhere.prototype.hideLoadingMessage = function() {

    var img = document.getElementById("myImg");

    if (img != null)

        img.style.display = "none";

}

11-27  重载后的Ajax请求提示信息

 

 

 

5.设置页面可刷新区域

AjaxAnywhere使用自定义标签<aa:zone>来划分页面区域,从而动态地指定页面可刷新区域。通过这种方法,只需要在页面适当位置中添加<aa:zone name=""></aa:zone>标签。对于已有的Web应用程序,几乎无须更改原有的代码,只须使用<aa:zone>标签指定更新区域。AjaxAnywhere会将<aa:zone>标签解析为<span id=""></span>的标记,并最终通过更新其innerHTML属性值来达到更新页面的目的。

区域划分好之后,需要告诉AjaxAnywhere哪些区域需要更新,即设置页面可刷新区域。AjaxAnywhere提供两种方式设置页面可刷新区域:客户端重载AjaxAnywhere对象的getZonesToReload()方法,或者服务器端调用AAUtil类的addZonesToRefresh(ServletReq uest request, String commaSeparatedZonesList)方法。

如果使用客户端重载的方式,则需要将<aa:zone name=""></aa:zone>所指定区域的name属性值组织成以逗号“,”分隔的字符串。例程11-35根据区域内的复选框选中情况来确定该区域是否可刷新。

例程11-35  重载AjaxAnywhere对象的getZonesToReload()方法

ref_All = false;

 

ajaxAnywhere.getZonesToReload = function (url){

    if (ref_All)

        return "document.all";

    var zones="";

    var form = this.findForm();

    for (var i=0;i<form.elements.length;i++){

        var el = form.elements[i];

        if (el.type=="checkbox" && el.checked)

            zones += el.value+",";

    }

    return zones;

}

如果使用服务器端设置的方式,则需要从request中或者其他地方获取指定的zone名称,调用AAUtil类的addZonesToRefresh(ServletRequest request, String commaSeparated ZonesList)并逐个将其保存。当然,在此之前应该将要刷新区域的名称以“zones=zoneNa me1,zoneName2的形式附加在请求中。例程11-36展示了这一过程。

例程11-36  调用AAUtil类的方法保存可刷新区域

<%

if (AAUtils.isAjaxRequest(request)) {

    String[] commaSeparatedZones = request.getParameterValues ("zones");

    for (int i = 0; commaSeparatedZones != null && i < commaSeparated Zones.length; i++) {

        String zone = commaSeparatedZones[i];

        AAUtils.addZonesToRefresh(request, zone);

    }

}

%>

 

 


试用AjaxAnywhere

 

 

读者可以从AjaxAnywhere的官方网站下载demo演示包,它是一个war工程包,可以直接部署在5.0以上版本的Tomcat服务器上。演示包中包含十二个AjaxAnywhere应用案例,包括级联的下拉列表、Web选项卡应用、JSF集成等,其部署到Tomcat后的首页效果如图11-28所示。

11-28  AjaxAnywhere演示包

演示包中不涉及JSF的案例全部都是用单纯的JSP代码编写的,或者内嵌在JSP页面中的Java代码块。虽然从MVC分离的角度看这种方式不尽合理,不过可以使案例尽量简单,不依赖于任何的MVC框架。AjaxAnywhere本身对此并无要求。

而且,其中全部的JSP页面中的表单都提交到页面本身,比如,忽略formaction属性。在实际的应用程序中,可以将表单提交到任何URL中,只要保证这个URL最终将导向(forward,不是redirect)包含指定刷新区域的JSP页面。

接下来将AjaxAnywhere部署到本章的开发目录中,并且用AjaxAnywhere改造一下案例1数据校验。复制ajaxanywhere-1.1.0.6.jar{APPLICATION_HOME}/webapps/ WEB-INF/lib文件夹,复制aa.jsAjaxCh11文件夹。修改案例1中例程6-5sample6_2.jsp如例程11-37所示。

例程11-37  修改后的数据校验ajaxRegister.jsp

<%@ page contentType="text/html; charset=gb2312"%>

<%@ page import="com.ajaxlab.ajax.*"%>

<%@ taglib uri="http://ajaxanywhere.sourceforge.net/" prefix="aa" %>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>Ch11—案例:数据校验</title>

<link href="../css/style.css" rel="stylesheet" type="text/css">

<script language="javascript" src="aa.js"></script>

<script language="javascript">

ajaxAnywhere.formName = "form1";

ajaxAnywhere.getZonesToReload = function() {

    return "feedback_info";

}

function doCheck() {

    var f = document.forms[0];

    if((f.username.value!="")||(f.email.value!="")) {

        if(f.email.value!="") {

                var pattern = /^[/w./-/_]+@{1}/w+(/.{1}/w+)+$/;

                var result = pattern.exec(f.email.value);

                if(result==null) window.alert("电子邮件格式错误请按标准email名称格式填写,hello@sohu.com");

        }

        f.action = "ajaxRegister.jsp";

        ajaxAnywhere.submitAJAX();

    }

}

function formSubmit() {

    var f = document.forms[0];

    f.action = "login.jsp";

    f.submit();

}

</script>

</head>

 

<body><center>

<form name="form1" method="post" action="login.jsp">

    <table width="500" border="0" cellspacing="0" cellpadding="4">

        <caption>用户注册</caption>

        <tr>

            <td width="70">用户名称:</td>

            <td width="414"><input name="username" type="text" class="f orm_ text" id="username" size="40">

            <input name="userCheck" type="button" class="button" id= " userCheck" value="惟一性检查" onClick="doCheck()">

            </td>

        </tr>

        <tr>

            <td>密码:</td>

            <td><input name="password" type="password" class="form_tex t" id="password" size="40"></td>

        </tr>

        <tr>

            <td>电子邮件:</td>

            <td><input name="email" type="text" class="form_text" id= "email" size="40">

            <input name="emailCheck" type="button" class="button" id= "emailCheck" value="惟一性检查" onClick="doCheck()">

            </td>

        </tr>

        <tr>

            <td colspan="2">

            <font color="#FF0000">

            <aa:zone name="feedback_info">

            <%

            String username = request.getParameter("username");

            String email = request.getParameter("email");

            UserService service = new UserService();

            if((username!=null)&&(!"".equals(username))) {

                UserValue user = service.findUserByName(username);

                if(user!=null) out.println("用户名称["+username+"]已经被注册,请更换其他用户名称再注册。<br>");

                else out.println("用户名称["+username+"]尚未被注册,您可以继续。<br>");

            }

            if((email!=null)&&(!"".equals(email))) {

                UserValue user = service.findUserByEmail(email);

                if(user!=null) out.println("电子邮件["+email+"]已经被注册,请更换其他用户名称再注册。");

                else out.println("电子邮件["+email+"]尚未被注册,您可以继续。");

            }

            %>

            </aa:zone>

            </font>

            </td>

        </tr>

        <tr align="center">

            <td colspan="2"><input name="Submit" type="submit" class= "button" value="提交" onClick="formSubmit();return false;"></td>

        </tr>

    </table>

</form>

</center>

</body>

</html>

例程11-37引用了AjaxAnywhereJavascript库文件aa.js,并设置AjaxAnywhere对象的formNameform1,重载其getZonesToReload方法指定更新区域为feedback_info。事件处理函数doCheck()调用AjaxAnywhere对象的submitAJAX()方法,向服务器提交Ajax请求,并进行数据校验。页面上则使用了<aa:zone name="feedback_info"></aa:zone>标签指定原来<label>标记所定义的区域为页面可刷新区域,该标签最终被解析成<span id="feedback_ info"></span>。原来在register.jsp中的数据校验逻辑也整合到ajaxRegister.jsp中了。当单击“惟一性检查”按钮的时候,AjaxAnywhere向服务器提起数据校验请求,随后将校验结果显示在可刷新区域feedback_info,如图11-29所示。

 

 

Ajax Anywhere的适用范围

 

 

AjaxAnywhereAjax进行封装,以对象的形式实现Ajax的各种操作,将其统一到一个Javascript文件中。在页面实现上,AjaxAnywhere新颖的以划分页面区域的方式,实现不重载刷新的更新页面内容。通过这几种方式,AjaxAnywhere确实能够在一定程度上降低Ajax开发应用的难度和门槛,尤其是对DOM不是很熟悉的开发人员。另外,AjaxAnywhere对于JSF这种特别接近桌面应用程序GUIMVC框架也提供了兼容性良好的Ajax应用支持。

为保持其灵活性,AjaxAnywhere提供了丰富的自定义功能,完全可以通过重载aa.jsAjaxAnywhere对象的相关方法来实现符合自己业务需求和特色的Ajax功能。不过这要求对本节所提到的AjaxAnywhere类库及其用法有比较深入的了解。

AjaxAnywhere使用过滤器Filter的方式对其所部署的Web应用程序中的指定http请求应用Ajax,可以通过控制过滤器Filter的配置实现对不同请求处理方式的选择。另外,为报纸整个Ajax框架具备平滑的兼容性,AjaxAnywhere允许在传统的通信方式和Ajax之间做必要的切换。

DWRAjax Tags相比,AjaxAnywhere既不需要对客户端暴露服务器端Java类的接口,又能够快速方便地改造已有的Web应用程序,更加符合MVC所倡导的实现原则。如果读者希望对AjaxAnywhere有更加深入的了解,可以从其官方网站下载其全部源代码分析一下。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics