何为Ajax?
Ajax不是什么新技术,是Asynchronous JavaScript and XML的简称. 它是javascript和xml等技术应用的结合。具体包括:
- DHTML和CSS
- 使用文档对象模型(Document Object Model)作动态显示和交互
- 使用XML和XSLT做数据交互和操作
- 使用XMLHttpRequest进行异步数据接收
- 使用JavaScript将它们绑定在一起
有了Ajax技术,我们可以在一定程度上实现Rich Internet Client界面。我们来看一个例子。要设计一个Web界面,用户从下拉式列表中选择一个省份,在另一个清单式列表中显示该省份的城市清单。而这些省份所拥有的城市数据是储存在服务器端数据库中的。在没有Ajax之前,用户在浏览器上每选择一次省份,则发生一次表单提交动作,将所选省份通过表单的POST请求发送到Servlet/jsp,然后服务器又返回另一个Web页面,里面包含该省份的数据。而用户在浏览器中所看到的就是页面被重新刷新了一次,会有明显的界面迟滞效果。
在Ajax技术出现之后,这一切都成为过去。用户看到的几乎是即时刷新的Web界面。后面我们会详细讨论如何在不同浏览器平台上实现这个例子,以及不同浏览器上编写脚本所就注意的事项。
XMLHttpRequest---Ajax的灵魂
要在浏览器上实现Ajax应用,需要创建一个XMLHttpRequest脚本对象,我们就是通过此对象来让javascript与服务器进行后台的异步交互,而交互的媒介就是XML.
XMLHttpRequest并不是一个W3C规定的标准技术[1], 所以在不同的浏览器上,创建XMLHttpRequest对象的方式也不一样.
1) var xmlHttp; 2) if (window.XMLHttpRequest) 3) { 4) // 创建 Mozilla/FireFox平台的 XMLHttpRequest 对象 5) xmlHttp = new XMLHttpRequest(); 6) } else if (window.ActiveXObject) 7) { 8) // 创建 IE/Windows 平台的XMLHttp对象 9) xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); 10) }
以上代码就创建了XMLHttpRequest脚本对象. 其中第5行是FireFox平台上的创建方式, 我只在FireFox平台上测试过, 由于Firefox是采用Mozilla为内核,理论上也可以在Mozilla上运行.第9行是IE上的创建方式.
所幸的是, 虽然创建方式不一样,但这两种对象所提供的方法和属性几乎是一模一样的,
常用的方法有:
open("method","URL",async) "method"是数据提交的方式,一般有"POST","GET"等. "URL"是要开启的地址. async是指定是否用异步的方式处理请求. send(content) 'content'是要发送的数据内容. setRequestHeader("label","value") 设置请求头部信息,例如指定content type等等.
常用的属性有:
readyState 返回XMLHttpRequest对象的状态. onreadystatechange 这是一个对象状态发生变化的事件处理器. 你可以为此属性指定一个处理函数, 用事件驱动的方式来处理XMLHttpRequest返回的数据. 通常XMLHttpRequest对象采用异步的方式开启URL时使用此属性. responseXML 以XML文档对象方式返回服务器的响应数据. responseText 以文本方式返回服务器的响应数据.
XML DOM---沟通浏览器与服务器的桥梁
不管怎样, @3C为我们制定了XML DOM的规范, 而Mozilla或者Microsoft等浏览器厂商都承诺会在它们的浏览器中实现这个规范, 所以在用javascript解析xml dom时, 只要是用标准的dom对象, 基本上是可以跨平台运行的.
而对于DHTML的文档对象模型, 可就不那么幸运了, 例如我们要引用html页面中的一个表单元素,
<html> <body> <input name="abc" id="abc" type="text" value="hello"/> </body> </html>
在IE上,可以用以下的脚本来显示这个字段中的值:
alert(document.abc.text);
而在Mozilla/Firefox上就没那么好采了. 要用以下稍微麻烦一些的方式:
alert(document.getElementById("abc").text);
而Mozilla的这种方式正是W3C所规定的标准. 而IE也没有食言,这种语法在IE 6.0上也工作正常!
Ajax的无刷新Web应用
回到我们前面提到的案例, 我们用Ajax来做一个各省城市查询页面.
为了方便演示,我们的客户端页面采用htm格式, 服务器端采用jsp来处理请求.
在客户端页面,我们主要编写了2个javascript函数, 一个用来创建XMLHttpRequest请求和发送请求数据.另一个用来处理返回的xml文档数据.
// 从指定URL加载XML文档数据对象。 // @param url 请求地址 // @param reqText 请求数据 function loadXMLDoc(url,reqData) { try { var xmlHttp; if (window.XMLHttpRequest) { // 创建 Mozilla/FireFox平台的 XMLHttpRequest 对象 xmlHttp = new XMLHttpRequest(); } else if (window.ActiveXObject) { // 创建 IE/Windows 平台的XMLHttp对象 xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } // 用POST,非异步方式开启请求地址, xmlHttp.open("POST", url, false); // 设置提交数据的格式为Form表单格式。 // 如要发送xml格式的数据,将此行注释掉即可。 // 或者显式指定为"Content-Type", "text/xml; charset=utf-8" xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); // 发送数据 xmlHttp.send(reqData); // 返回xml文档数据对象 return xmlHttp.responseXML; }catch(exception) { //alert(exception); } } // 处理XML文档数据 function processData(param) { if ( param==null ) return; // 请求参数 var sParam = "country="+param; // 请求地址 var sUrl = "http://turbo:8080/qis/Ajax.jsp"; // 加载xml文档数据对象 var xmlDOM = loadXMLDoc(sUrl,sParam); // 下面开始将返回的xml数据解析出来,并添加到列表中。 var root = xmlDOM.documentElement; try { document.getElementById("city").length = 0; for (i=0;i<root.childNodes.length;i++) { sValue = root.getElementsByTagName('city')[i].firstChild.data; if(sValue!=null) { //将解析出来的城市名添加到清单列表中 document.getElementById('city').length = document.getElementById('city').length+1; document.getElementById('city').options[i].text=sValue; document.getElementById('city').options[i].value=sValue; } } }catch(exception) { //alert(exception); } }
其中第1个函数用来从指定URL加载XML文档数据对象, 返回一个XML DOM对象, 你可以用标准的dom对象方法来解析其中的数据. 这个方法几乎是通用的, 你也可以将它复制到你的Ajax的页面中使用. 而第2个函数处理返回的DOM数据,并将数据添加到指定的表单元素中显示. 注意, 为了跨浏览器使用, 我们的代码里引用表单元素的方法是document.getElementById. 如果你要将它移植到你的程序中,你得重写xml数据解析的代码.
在表单元素选择省份的下拉式清单上, 我们加了onchange事件, 将当前所选省份传给processData函数处理,
onchange="javascript:processData(this.value)
当选择省份时, 则马上调用processData函数, 从服务器端取数据.
而对于服务端程序, 为了部署简便, 我采用jsp来编写, 它主要负责处理用户请求, 并返回相应的xml文档数据, 其大致结构如下:
// 创建文档对象。 Document doc = DocumentBuilderFactory.newInstance() .newDocumentBuilder().newDocument(); // 创建文档对象根元素。 Element xmlRoot = doc.createElement("result"); String country = request.getParameter("country"); // 如果是广东省,创建广东省城市数据文档树。 if ( "GuangDong".equals(country) ) { ... } // 如果是湖北省,创建湖北省城市数据文档树。 else if ( "HuBei".equals(country) ) { ... } // 如果是湖南省,创建湖南省城市数据文档树。 else if ( "HuNan".equals(country) ) { ... } // 将文档根元素加到文档对象。 doc.appendChild(xmlRoot); // 将xml文档数据发送给客户端浏览器。 DOMSource doms = new DOMSource(doc); StreamResult sr = new StreamResult(response.getOutputStream( )); TransformerFactory tf = TransformerFactory.newInstance( ); Transformer t = tf.newTransformer( ); t.setOutputProperty("encoding", "UTF-8"); t.transform(doms, sr);
你需要针对你的实际应用来写这个处理用户请求的服务程序.其中创建xml文档的过程可以从你的Java Bean, 或者Hibernate的JDO对象等. 总之, 你可以将任何数据创建成xml文档对象.
演示源码下载
Ajax.htm.txt 这是演示程序的客户端Web页面.
Ajax.jsp.txt 这是服务器端处理用户请求的程序. 为了部署方便,我们它写成一个jsp格式.
将这2个程序下载后, 将后面的扩展名.txt去掉, 然后复制到你的Tomcat的webapps相应的目录下, 例如ROOT目录, 然后就可以通过下面的地址访问了:
http://localhost:8080/Ajax.htm
本演示程序在Firefox 1.x和IE 6.0上测试通过.