<Using AJAX With JAVA Technology>
原文地址:http://java.sun.com/developer/EJTechTips/2005/tt1122.html#1
中英对照:
by Greg Murray
作者:格雷格-默里
AJAX代表着异步的JAVASCRIPT和XML。本质上,AJAX是一种在WEB应用中通过网页与用户交互的有效方式,它减少了用户交互中刷新页面或 整页重载的频率。这样使用浏览器可以进行更丰富的动作(与桌面应用或基于PLUGIN的WEB应用相似)。AJAX交互在后台异步执行,此时用户可以继续 在这个页面上工作。AJAX是由网页中的JAVASCRIPT驱动的。当AJAX交互完成后,JS更新网页HTML代码。这个动作在不需要刷新页面的情况 下迅速执行。AJAX可以用于许多方面,例如在用户输入的同时用服务器端规则验证其输入,获得服务器端详细数据并主动更新页面数据,或者提交页面表单的部 分数据。
是什么让AJAX技术具体如此魅力呢?AJAX应用不需用单独的插件,并且是平台和浏览器中立的。也就是说,AJAX并不被旧的浏览器良好支持。但是不必 太过担心,你可以撰写跨不同浏览器的脚本。你应该考虑使用跨不同浏览器的JS库并且在一些情况下有选择性的使用交互技术以支持旧的浏览器。了解更多,请查 看JAVA开发者的AJAX FAQ。http://weblogs.java.net/blog/gmurray71/
那么JAVA技术适合在哪儿使用呢?
JAVA技术与AJAX搭配使用非常不错。JAVA技术为AJAX交互提供服务器端处理,通过servlets、JavaServer Pages (JSP)、JavaServer Faces (JSF) 及web服务。AJAX请求的编程模式使用与常规WEB应用相同的API。JSF技术可以用来创建可重用的组件,这些组件生成客户端JS并与服务器端 AJAX处理代码通信。下面让我们来看一个使用AJAX和SERVLETS的例子。
实例:自动完成
假设用户在一个网页中搜索雇员信息。这个页面包含一个输入域,用户在其中输入雇员的名字。在这个例子中输入域具有自动完成的功能。换句话说,用户输入雇员 名的一部分,WEB应用通过列出所有姓名以输入字母开头的雇员来帮助完成输入。自动完成功能让用户可以无需记住员工的全名或者从另一个页面查找名字。(此 句偶之前百思不得其解,后来经永华指点,大约是这样的:你可以有三种方式查询员工信息,1.记住员工的名字、2.从别的地方,比如其它页面找到后复制粘贴 过来,3.使用自动完成功能,很显然,第三种是最省事的,优于其它方式,所以说3 SAVE FROM 1/2.)
可以使用AJAX实现搜索输入域的自动完成。要实现这个,需要撰写相应的客户端和服务器端代码。
客户端
首先,用户打开一个网页。假设这个页面是一个由JSF组件、SERVLET或JSP产生的HTML页面。页面中包含一个表单文本域,它有一个ONKEYUP属性,其值为一个JS函数doCompletion()。这个每当文本域有输入改变,这个函数就会被调用。
<input type="text"
size="20"
autocomplete="off"
id="complete-field"
name="id"
οnkeyup="doCompletion();">
假设用户在表单文本域输入字母M,doCompletion()将被调用,初始化一个XMLHttpRequest对象。
function initRequest(url) {
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
} else if (window.ActiveXObject) {
isIE = true;
return new ActiveXObject("Microsoft.XMLHTTP");
}
}
function doCompletion() {
if (completeField.value == "") {
clearTable();
} else {
var url = "autocomplete?action=complete&id=" +
escape(completeField.value);
var req = initRequest(url);
req.onreadystatechange = function() {
if (req.readyState == 4) {
if (req.status == 200) {
parseMessages(req.responseXML);
} else if (req.status == 204){
clearTable();
}
}
};
req.open("GET", url, true);
req.send(null);
}
}
XMLHttpRequest对象现在还不是JS标准中的一部分(正在努力将其标准化),但它却是事实上的标准并且是AJAX的核心。这个对象对于在HTTP协议上与服务器端组件(此例中是一个SERVLET)交互很可靠.
当创建XMLHttpRequest对象时需指定三个参数:一个URL,HTTP方式(GET或POST), 交互是否异步。在这个XMLHttpRequest 例子中,这些参数如下:
* The URL autocomplete, and the text from the complete-field (an M character):
*自动完成的URL和从输入域键入的文字:
var url = "autocomplete?action=complete&id=" +
escape(completeField.value);
* GET, signifying the HTTP interactions uses the GET method, and true, signifying that the interaction is asynchronous:
*GET,表示HTTP交互使用GET方法;TRUE,表示交互是异步的:
req.open("GET", url, true);
当使用异步调用时,需要建立一个回调函数。HTTP交互中当XMLHttpRequest中的readyState属性改变时,回调函数被异步调用。此例 中回调函数是processRequest()。它为一个函数建立了一个XMLHttpRequest.onreadystatechange属性。(前 两句还不太明白什么意思——译者注)。注意当readyState为4时对parseMessages函数的调用。 XMLHttpRequest.readyState为4意味着HTTP交互的成功完成。
HTTP交互以调用XMLHttpRequest.send()开始。如果交互是异步的,浏览器前继续执行页面事件(而不是中断用户当前动作去执行交互动作——译者注)。
服务器端
XMLHttpRequest为自动完成的URL产生了一个HTTP GET请求,这个URL被映射到一个名为AutoComplete的Servlet上。AutoComplete servlet的doGet() 方法被调用。这里的doGet()方法如下:
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
...
String targetId = request.getParameter("id");
Iterator it = employees.keySet().iterator();
while (it.hasNext()) {
EmployeeBean e = (EmployeeBean)employees.get(
(String)it.next());
if ((e.getFirstName().toLowerCase().startsWith(targetId) ||
e.getLastName().toLowerCase().startsWith(targetId))
&& !targetId.equals("")) {
sb.append("<employee>");
sb.append("<id>" + e.getId() + "</id>");
sb.append("<firstName>" + e.getFirstName() +
"</firstName>");
sb.append("<lastName>" + e.getLastName() +
"</lastName>");
sb.append("</employee>");
namesAdded = true;
}
}
if (namesAdded) {
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
response.getWriter().write("<employees>" +
sb.toString() + "</employees>");
} else {
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
}
如你在SERVLET中所看到,不需要为写服务器端AJAX处理代码而学习新知识。当你想要发送XML文档,只需将响应内容类型设置为text/xml。 使用AJAX,你甚至可以发送普通文本或者小段JS代码,这些代码可能在客户端被回调函数计算或执行。注意:一些浏览器可能将结果缓存,所以有必要设置 Cache-Control HTTP header为no-cache。此例中,SERVLET产生一个XML文档,它包含所有姓或名以M开头的雇员的姓名。下面是一个返回给 XMLHttpRequest对象的XML文档例子:
<employees>
<employee>
<id>3</id>
<firstName>George</firstName>
<lastName>Murphy</lastName>
</employee>
<employee>
<id>2</id>
<firstName>Greg</firstName>
<lastName>Murphy</lastName>
</employee>
<employee>
<id>11</id><firstName>Cindy</firstName>
<lastName>Murphy</lastName>
</employee>
<employee>
<id>4</id>
<firstName>George</firstName>
<lastName>Murray</lastName>
</employee>
<employee>
<id>1</id>
<firstName>Greg</firstName>
<lastName>Murray</lastName>
</employee>
</employees>
再来看客户端
当最初发送请求的XMLHttpRequest对象收到回应,它调用parseMessages() 函数(参见此例前面XMLHttpRequest的初始化)。这个函数如下:
function parseMessages(responseXML) {
clearTable();
var employees = responseXML.getElementsByTagName(
"employees")[0];
if (employees.childNodes.length > 0) {
completeTable.setAttribute("bordercolor", "black");
completeTable.setAttribute("border", "1");
} else {
clearTable();
}
for (loop = 0; loop < employees.childNodes.length; loop++) {
var employee = employees.childNodes[loop];
var firstName = employee.getElementsByTagName(
"firstName")[0];
var lastName = employee.getElementsByTagName(
"lastName")[0];
var employeeId = employee.getElementsByTagName(
"id")[0];
appendEmployee(
firstName.childNodes[0].nodeValue,
lastName.childNodes[0].nodeValue,
employeeId.childNodes[0].nodeValue);
}
}
parseMessages() 函数接收AutoComplete servlet返回的XML文档对象做为参数。该函数自动转化XML文档并更新网页内容,通过在HTML源文件中为XML文档中的姓名插入一个 id 为 "menu-popup"的DIV元素:
<div style="position: absolute;
top:170px;left:140px" id="menu-popup">
当用户输入更多字符,姓名列表变短。用户可以点击要查找的姓名。
希望现在你已经了解到AJAX如何在后台简单地交换信息以及在此基础上动态地更新页面。欲了解更多关于AJAX和JAVA技术,可以看这篇技术文章 《Asynchronous JavaScript Technology and XML (AJAX) With Java 2 Platform, Enterprise Edition》(http: //java.sun.com/developer/technicalArticles/J2EE/AJAX/index.html)。或者看AJAX 蓝图http://java.sun.com/blueprints/ajax.html,或Greg Murray的博客中为JAVA开发者写的AJAX FAQ。http://weblogs.java.net/blog/gmurray71/
关于作者
格雷格-默里是SERVLET规范领导。他曾是JAVA蓝图工作组会员,非常负责地对WEB TIER提出许多建议(或者是对XX负责)。在蓝图工作组的协助下他在SUN领导AJAX工作。格雷格在国际化、WEB服务、J2SE独立客户端和基于 AJAX的WEB客户端方面有着丰富的经验。