17.6 使用Ajax
了解了“Ajax是什么”、“Ajax能做什么”以及“在哪些地方使用Ajax”,相信读者都迫不及待地想知道如何使用Ajax。前面几节曾提过,Ajax不是一种新技术,而是几种成熟技术的组合,其中最为核心的是JavaScript脚本、实现异步通信的XMLHttpRequest对象(本书第16章)以及文档对象模型DOM(本书第5章及第15章)。在学习如何使用Ajax前,读者务必熟练掌握上述内容。本小节从简单的Ajax开发框架入手,逐步介绍Ajax在三种经典应用场景的使用,并配合实例讲解,其中包括:
数据验证——注册用户名唯一性验证实例;
按需读取数据——级联目录实例;
自动实时更新页面——自动实时刷新页面实例。
XMLHttpRequest对象是实现Ajax应用必不可少的核心技术,负责Ajax与服务器的异步交互,故Ajax应用实现的框架和异步通信的架构类似,也是围绕XMLHttpRequest对象的创建、发送请求、处理响应来展开的。
与前面章节介绍的客户端与服务器通信的框架类似,一个简单的Ajax框架一般包括三部分:XMLHttpRequest对象的创建、向服务器发送请求、处理服务器返回的数据并动态显示或者更新页面,下面分别予以详细论述。
17.6.1
创建XMLHttpRequest对象
在本书前面的章节中已详细介绍了不同浏览器平台创建XMLHttpRequest对象的方法,其中也包括跨浏览器平台的智能HTTP请求,但其函数体均比较庞大,下面列举一种简单的创建方法,其代码如下所示:
function createXMLHTTP()
{
var request;
var browser = navigator.appName;
//使用IE,则使用MSXML创建XMLHTTP对象
if(browser == "Microsoft Internet Explorer")
{
var arrVersions = ["MSXML2.XMLHttp.5.0 ", "MSXML2.XMLHttp.4.0",
"MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"," Microsoft.XMLHttp "];
for(var i=0; i < arrVersions.length; i++)
{
try
{
//从中找到一个支持的版本并建立XMLHTTP对象
request = new ActiveXObject(arrVersions[i]);
return request;
}
catch(exception)
{
//忽略,继续
}
}
}
//Mozilla等浏览器
else
{
//否则返回一个XMLHttpRequest对象
request = new XMLHttpRequest();
return request;
}
}
17.6.2
向服务器发送请求
利用上面的创建函数创建XMLHTTP对象实例,向对应的服务器发送请求,可以是GET请求,也可以是POST请求,区别请参考第16章相关内容。本章为了简单起见,都以GET请求为例。简单的发送请求函数如下所示:
function Send_Request(url)
{
//创建XMLHTTP对象实例
var http_req=createXMLHTTP();
//Open函数建立连接,一定是异步方式
http.open("GET", url, true);
//声明回调函数,也可以像第16章一样直接写在后面
http_req.onreadystatechange = processRequest;
//发送请求
http_req.send(null);
}
17.6.3
处理服务器响应
在上一步声明的回调函数中,接收服务器返回的数据,并根据需求动态地更新页面(一般使用DOM协助完成)或者进行一些其他的操作(如弹出警告框等)。一个简单的处理函数如下所示:
function processRequest()
{
//4表示请求已完成
if(http_req.readyState == 4)
{
if(http_req.status==200)
{
//获取服务段的响应文本
var ResponseStr = http_req.responseText;
//处理返回数据,这里只是把数据以警告框的方式显示
alert(ResponseStr);
}
else
{
alert("请求页面异常!");
}
}
}
17.6.4
完整的Ajax框架
综合创建XMLHttpRequest对象、向服务器发送请求和处理服务器响应三个步骤,得到完整的Ajax框架,代码如下所示:
<script language="JavaScript" type="text/javascript">
<!--
//全局对象实例
var http_req=false;
//创建函数
function createXMLHTTP()
{
var request;
var browser = navigator.appName;
//使用IE,则使用MSXML 创建XMLHTTP对象
if(browser=="Microsoft Internet Explorer")
{
var arrVersions = ["MSXML2.XMLHttp.5.0 ", "MSXML2.XMLHttp.4.0",
"MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"," Microsoft.XMLHttp "];
for (var i=0; i < arrVersions.length; i++)
{
try
{
//从中找到一个支持的版本并建立XMLHTTP对象
request = new ActiveXObject(arrVersions[i]);
return request;
}
catch (exception)
{
//忽略,继续
}
}
}
//Mozilla等浏览器
else
{
//否则返回一个XMLHttpRequest对象
request = new XMLHttpRequest();
return request;
}
}
//实例化XMLHTTP对象
http_req=createXMLHTTP();
//发送请求
function Send_Request(url)
{
//创建XMLHttp对象实例
//Open函数建立连接,一定是异步方式
http.open("GET", url, true);
//声明回调函数,也可以像第16章一样直接写在后面
http_req.onreadystatechange = processRequest;
//发送请求
http_req.send(null);
}
//处理函数
function processRequest()
{
//4表示请求已完成
if(http_req.readyState == 4)
{
if(http_req.status==200)
{
//获取服务端的响应文本
var ResponseStr = http_req.responseText;
//处理返回数据,这里只是把数据以警告框的方式显示
alert(ResponseStr);
}
else
{
alert("请求页面异常!");
}
}
}
-->
</script>
上面几个小节介绍了如何创建完整的Ajax框架,下面通过编写“Hello,Ajax”程序的实例来讲述Ajax程序的开发过程。
17.6.5
开山之作:“Hello,Ajax”程序
类似于C++、Java等高级语言,下面以“Hello,Ajax”程序为例,简单介绍Ajax技术的应用方法,客户端页面对应的文档“HelloAjax.html”的代码如源程序17.1所示。
//源程序17.1
<!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html140/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>AJAX使用框架 ---- Hello,Ajax!</title>
<script language="JavaScript" type="text/javascript">
<!--
function createXMLHTTP()
{
var request;
var browser = navigator.appName;
//若浏览器为IE,则使用XMLHTTP对象
if(browser == "Microsoft Internet Explorer")
{
var arrVersions = ["Microsoft.XMLHttp", "MSXML2.XMLHttp.4.0",
"MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp","MSXML2.XMLHttp.5.0"];
for (var i=0; i < arrVersions.length; i++)
{
try
{
//从中找到一个支持的版本并建立XMLHTTP对象
request = new ActiveXObject(arrVersions[i]);
return request;
}
catch(exception)
{
//忽略,继续
}
}
}
else
{
//否则返回一个XMLHttpRequest对象
request = new XMLHttpRequest();
return request;
}
}
//全局XMLHttpRequest对象实例
var http = createXMLHTTP();
//发送请求函数
function HelloWorld()
{
var username = document.forms[0].username.value;
var url = "helloHandle.jsp?username="+escape(username);
//指定服务端的地址
http.open("GET", url, true);
//声明回调函数
http.onreadystatechange = getHello;
//发送请求
http.send(null);
}
//回调函数,响应状态变化事件
function getHello()
{
// readyState=4表示请求已完成
if (http.readyState == 4)
{
//获取服务端的响应文本
var helloStr = http.responseText;
//插入响应到ID为"ajax-ServerBack"的DIV标签内
document.getElementById("ajax-ServerBack").innerHTML = helloStr;
}
}
-->
</script>
</head>
<body >
<table with="50%">
<tr>
<td align='center'><h2>Hello,Ajax!</h2></td>
</tr>
<tr><td><hr></td></tr>
<tr>
<td>
<form>
Name:<input type="text" name="username" value="" >
</form>
</td>
</tr>
<tr>
<td align="center">
<input type="button" name="" value="Say Hello to Ajax" onClick="HelloWorld()">
</td>
</tr>
<tr>
<td>
<div id="ajax-ServerBack" style="background:#ffffee;border:solid #cccccc"> </div>
</td>
</tr>
</table>
</body>
</html>
请求的服务器端页面(helloHandle.jsp)实现非常简单,只要取得请求参数,并以字符串的方式返回“Hello”信息即可,代码如源程序17.2所示。
//源程序17.2
<%@ page contentType="text/html; charset=gb2312" language="java" %>
<%
String username = request.getParameter("username");
String responseText=" 服务器返回:<br> Hello "+username+"! ----Ajax <br>";
out.print(responseText);
%>
把上述两页面放在JSP服务器的webapps\ajax目录下(JSP服务器的安装配置,请参考相关书籍),在浏览器的地址栏中输入:http://localhost:8080/ajax/HelloAjax.html,结果页面如图17.8所示。
在文本框中输入“Yang ShuiQing”,单击“Say Hello to Ajax”按钮,页面无须刷新,动态更新显示服务器返回的数据,其运行结果如图17.9所示。

图17.8 Hello Ajax原始页面 图17.9 Hello Ajax动态更新
17.6.6
注册信息实时验证实例
利用Ajax来实时验证数据,是Ajax经典应用场景之一。在Web应用中,很多时候需要填写表单,而表单中的一些项需要验证,例如客户注册应用,要进行用户名的唯一性验证。传统的Web模式对数据验证方法有其不足,而Ajax很好地克服了这些缺点,提供了更好的用户体验。
下面来看一个完整的Ajax实现用户名唯一性验证的实例,主页面对应的文档“register.jsp”包含了Ajax应用的三个完整部分:XMLHttpRequest对象的创建、向服务器发送请求、处理服务器返回的数据并动态显示或者更新页面,其代码如源程序17.3所示。
//源程序17.3
<%@page language="java" contentType="text/html;charset=GBK"%>
<! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html140/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Ajax用户注册演示程序</title>
<script language="javascript" type="text/javascript">
<!--
//创建函数
function createXMLHTTP()
{
var request;
var browser = navigator.appName;
//使用IE,则使用XMLHTTP对象
if(browser == "Microsoft Internet Explorer")
{
var arrVersions = ["Microsoft.XMLHttp", "MSXML2.XMLHttp.4.0",
"MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp","MSXML2.XMLHttp.5.0"];
for (var i=0; i < arrVersions.length; i++)
{
try
{
//从中找到一个支持的版本并建立XMLHTTP对象
request = new ActiveXObject(arrVersions[i]);
return request;
}
catch (exception)
{
//忽略,继续
}
}
}
else
{
//否则返回一个XMLHttpRequest对象
request = new XMLHttpRequest();
if(request.overrideMimeType)
{
request.overrideMimeType('text/xml');
}
return request;
}
}
//全局XMLHTTP对象实例变量
var http = createXMLHTTP();
//发送请求
function chkUser()
{
//请求"CheckUserName" ServLet
var url = "CheckUserName";
var name = document.getElementById("userName").value;
url += ("?userName="+escape(name)+"&oprate=chkUser");
http.open("GET",url,true);
http.onreadystatechange = ProcessHttpResponse;
http.send(null);
return ;
}
//处理响应
function ProcessHttpResponse()
{
if(http.readyState == 4)
{
if(http.status == 200)
{
var xmlDocument = http.responseXML;
if(http.responseText!="该用户名有效,可以使用!")
{
//返回的信息动态显示
document.getElementById("showStr").style.display = "";
document.getElementById("userName").style.background= "#FF0000";
document.getElementById("showStr").innerText = http.responseText;
}
else
{
document.getElementById("userName").style.background= "#FFFFFF";
document.getElementById("showStr").style.display = "";
document.getElementById("showStr").innerText = http.responseText;
}
}
else
{
alert("你所请求的页面发生异常,可能会影响你浏览该页的信息!");
alert(http.status);
}
}
}
//检验输入密码
function chkpassword()
{
var m=document.form1;
if(m.password.value.length>20 || m.password.value.length<6 )
{
document.getElementById("passwordStr").style.display = "";
document.getElementById("password").style.background= "#FF0000";
document.getElementById("passwordStr").innerText = "对不起,密码必须为英文字母、数字或下划线,长度为6~20!";
}
else
{
document.getElementById("password").style.background= "#FFFFFF";
document.getElementById("passwordStr").style.display = "none";
}
}
//验证两次密码是否一致
function chkconfirmPassword()
{
var m=document.form1;
if (m.password.value != m.confirmPassword.value)
{
document.getElementById("confirmPasswordStr").style.display = "";
document.getElementById("confirmPassword").style.background= "#FF0000";
document.getElementById("confirmPasswordStr").innerText = "对不起,密码与重复密码不一致!";
}
else
{
document.getElementById("confirmPassword").style.background= "#FFFFFF";
document.getElementById("confirmPasswordStr").style.display = "none";
}
}
//验证E-mail是否有效
function chkEmail()
{
var m=document.form1;
var email = m.email.value;
var regex = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/;
var flag = regex.test(email);
if(!flag)
{
document.getElementById("emailStr").style.display = "";
document.getElementById("email").style.background= "#FF0000";
document.getElementById("emailStr").innerText = "对不起,电子邮件地址无效!";
}
else
{
document.getElementById("email").style.background= "#FFFFFF";
document.getElementById("emailStr").style.display = "none";
}
}
//提交检查函数
function SubmitCheck()
{
var m=document.form1;
if(m.userName.value.length==0)
{
alert("对不起,用户名必须为英文字母、数字或下划线,长度为5~20。");
m.userName.focus();
return false;
}
if(m.password.value.length==0)
{
alert("对不起,密码必须为英文字母、数字或下划线,长度为5~20。");
m.password.focus();
return false;
}
if (m.password.value != m.confirmPassword.value)
{
alert("对不起,密码与重复密码不一致!");
m.confirmPassword.focus();
return false;
}
if(m.email.value.length==0)
{
alert("对不起,电子邮件地址不能为空!");
m.email.focus();
return false;
}
m.submit();
}
-->
</script>
<body>
<center>
<form name="form1" method="post" action="/Control?act=Register">
<h3 align="center">Ajax用户注册程序</h3>
<table align="center" width="500" border="1" >
<tr>
<td><font color="red">*</font></td>
<td width="100">用户账号:</td>
<td><input type="text" name="userName" maxlength="20"
style="background=#FFFFFF" onBlur="chkUser()"></td>
<td><div id="showStr" style="background-color:#FF9900;display:none"> </div> </td>
</tr>
<tr>
<td><font color="red">*</font></td>
<td>用户密码:</td>
<td align="left"><input type="password" name="password" maxlength="22"
style="background=#FFFFFF" onBlur="chkpassword()"/> </td>
<td><div id="passwordStr" style="background-color:#FF9900;display:none"> </div></td>
</tr>
<tr>
<td><font color="red">*</font></td>
<td>确认密码:</td>
<td><input type="password" name="confirmPassword" maxlength="20"
style="background=#FFFFFF" onBlur="chkconfirmPassword()"/></td>
<td><div id="confirmPasswordStr"
style="background-color:#FF9900;display:none"></div></td>
</tr>
<tr>
<td><font color="red">*</font></td>
<td>Email:</td>
<td><input type="text" name="email" maxlength="100" style="background= #FFFFFF"
onBlur="chkEmail()"></td>
<td><div id="emailStr" style="background-color:#FF9900;display:none"> </div></td>
</tr>
</table>
<div align="center">
<form>
<input type="button" name="ok" value="确定 " onclick="SubmitCheck()">
<input type="reset" name="reset" value="取消 ">
</form>
</div>
</center>
</body>
</html>
从上面的请求函数可以看出,目标页面(register.jsp)请求“CheckUserName”,后者为服务器端的Servlet程序(CheckUserName.java),在其中声明了一个字符串列表来保存已经使用过的用户名,而GET请求响应函数获得请求的用户名参数,判断是否已存在并把判断结果返回客户端。服务器端文档“CheckUserName.java”的代码如源程序17.4所示。
//源程序17.4
package check;
import java.io.PrintWriter;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CheckUserName extends HttpServlet
{
private String msgStr="";
//已注册名字列表
public String[] usernameList;
//响应GET请求函数
protected void doGet(HttpServletRequest request,HttpServletResponse response) throws
ServletException
{
String oprate=(String)request.getParameter("oprate");
String userName=(String)request.getParameter("userName");
try
{
if(oprate.equals("chkUser"))
{
response.setContentType("text/html;charset=GB2312");
if(userName.length()<6||userName.length()>20)
{
msgStr="对不起,用户名必须为字母、数字或下划线,长度为6-20个字符!";
}
else
{
boolean bTmp=this.IsContain(userName); //查找数据库中有无该用户名
if(bTmp)
msgStr="对不起,此用户名已经存在,请更换用户名注册!";
else
msgStr="该用户名有效,可以使用!";
}
response.getWriter().write(msgStr);
}
}//try
catch(Exception ex){}
}//doget
//处理POST请求函数
protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException
{
doGet(request,response);
}
//Servlet初始函数
public void init(ServletConfig config) throws ServletException
{
//初始已注册用户名字列表
usernameList=new String []{"Tomny","yangshuiqing","huoguangcheng"};
}
//判断用户名是否已经存在
private boolean IsContain(String param)
{
for (int i=0;i<usernameList.length ;i++ )
{
if(usernameList[i].equals(param))
{
return true;
}
else
continue;
}
return false;
}
} //End of Class
编译“CheckUserName.java”文件生成“CheckUserName.class”,将它放置于JSP服务器的webapps\ajax\WEB-INF\classes文件夹下,并修改WEB-INF\ajax\web.xml 文件(关于Servlet的配置,请参考相关书籍)。同时,将目标文件“register.jsp”放在JSP服务器下,使用浏览器载入http://local:8080/ajax/register.jsp,其结果如图17.10所示。
在“用户账号”对应的文本框中输入“yangshuiqing”,将输入焦点移离该文本框后,页面在不刷新的情况下与服务器异步交互,判断当前输入的用户名是否有效,并把判断的结果动态返回,如图17.11所示。

图17.10 Ajax注册原始页面 图17.11 实时判断用户名无效
若在“用户账号”对应的文本框中输入“HelloAjax”,服务器判断为有效用户名,结果如图17.12所示。
同时,页面中也加入了对密码、E-mail地址的判断,在对应的文本框中输入相关信息后将输入焦点移出该文本框,均可得到判断结果,如图17.13所示。

图17.12 用户名有效 图17.13 页面判断效果
17.6.7 级联目录实例
按需读取数据是Ajax技术的最大特色。按需读取数据,减少数据冗余,大大降低了服务器的负担,同时也提高了带宽的利用率,对Web应用中的分类树或树型结构操作非常有效,使用Ajax实现级联目录成为一种趋势。
考察源程序17.5使用Ajax技术实现的级联目录的实例代码(tree.jsp):
//源程序17.5
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Ajax级联测试程序.jsp</title>
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is an Ajax Test page">
</head>
<script language="JavaScript" type="text/javascript">
<!--
//创建函数
function createXMLHTTP()
{
var request;
var browser = navigator.appName;
if(browser == "Microsoft Internet Explorer")
{
var arrVersions = ["Microsoft.XMLHttp", "MSXML2.XMLHttp.4.0",
"MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp","MSXML2.XMLHttp.5.0"];
for (var i=0; i < arrVersions.length; i++)
{
try
{
//从中找到一个支持的版本并建立XMLHTTP对象
request = new ActiveXObject(arrVersions[i]);
return request;
}
catch(exception)
{
//忽略,继续
}
}
}
else
{
//否则返回一个XMLHttpRequest对象
request = new XMLHttpRequest();
if(request.overrideMimeType)
{
request.overrideMimeType('text/xml');
}
return request;
}
}
var req=createXMLHTTP();
//发送请求
function Send_Request(stateVal)
{
var url = "SelectCity?state="+stateVal;
if(req)
{
req.open("GET",url, true);
req.onreadystatechange=processRequest;
req.send(null);
}
}
//处理响应
function processRequest()
{
if(req.readyState == 4)
{
if(req.status == 200)
{
//XML DOM操作,取出city标记节点
var city = req.responseXML.getElementsByTagName("city");
var str=new Array();
for(var i=0;i<city.length;i++)
{
//把XML DOM节点的值读出
str[i]=city[i].firstChild.data;
}
buildSelect(str,document.getElementById("city"));
}
else
{
alert("请求页面发生异常!");
}
}
}
//动态添加级联选项
function buildSelect(str,sel)
{
sel.options.length=0;
for(var i=0;i<str.length;i++)
{
sel.options[sel.options.length]=new Option(str[i],str[i])
}
}
-->
</script>
<body>
<h3>Ajax级联测试程序</h3><hr>
<form>
<select name="state" onChange="Send_Request(this.value)">
<option value="">省份</option>>
<option value="hn">HUNAN</option>>
<option value="gd">GUANGDONG</option>>
</select>
<select id="city">
<option value="">城市</option>
</select>
</form>
</body>
</html>
上述代码对应的主页面请求一个Servlet(SelectCity.java),后者判断客户端请求的是什么省份(一级目录),并把所选省份对应的城市(二级目录)以XML文档的方式发回客户端,其代码如源程序17.6所示。
//源程序17.6
package select;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SelectCity extends HttpServlet
{
public SelectCity()
{
super();
}
public void destroy()
{
super.destroy();
}
//响应GET请求函数
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
String state = request.getParameter("state");
StringBuffer sb=new StringBuffer("<state>");
if ("hn".equals(state))
{
sb.append("<city>changsha</city><city>xiangtan</city><city>zhuzhou </city>");
}
else if("gd".equals(state))
{
sb.append("<city>guangzhou</city><city>shaoguan</city><city>zhanjiang </city>");
}
sb.append("</state>");
PrintWriter out=response.getWriter();
out.write(sb.toString());
out.close();
}
}
按照第17.6.6节“注册信息实时验证实例”中讲述的方法,将服务器端响应文件“SelectCity.java”编译为“SelectCity.class”并配置JSP服务器,使用浏览器载入http://localhost:8080/tree.jsp,其结果如图17.14所示:
选择一级目录“HUNAN”,则对应的二级目录:“changsha、xiangtan、zhuzhou”等城市作为选项在第二个下拉框中显示,如图17.15所示。

图17.14 级联目录实例 图17.15 一级目录HUNAN对应的二级目录
如选择一级目录“GUANGDONG”,则对应的二级目录:“guangzhou、shaoguan、zhanjiang”等城市作为选项在第二个下拉框中出现,如图17.16所示。

图17.16 一级目录GUANGDONG对应的二级目录
在该实例中,每次交互都只是读取对应的二级目录,按用户的需要读取数据,大大减少数据冗余,提高带宽利用率。该实例交互数据量较小,比较还不是很明显,如果交互数据量很庞大时,Ajax性能的提高是非常显著的。这也是Ajax受到追捧的原因之一。
17.6.8
自动实时更新页面
在信息千变万化的当今时代,Web应用的数据变化也是十分迅速的,例如新闻信息、天气预报、实时的聊天内容还有现在比较火的股市动态等。而在传统的Web应用中,用户为了得到相关新的内容,不得不反复刷新页面,或者页面实现定时刷新。刷新意味着装载页面,不但要载入更新的内容,原本已经加载的旧内容也要加载一遍,浪费带宽的同时,用户等待时间也相对较长。而在实时动态更新页面方面,Ajax有着得天独厚的优势,因此自动更新页面也是Ajax的经典应用之一。
在下面的实例中用户无须不停地刷新页面,页面会每隔一分钟和服务器自动交互一次,获得服务器系统时间,并动态更新数据到客户端页面。文档“newTime.jsp”的代码如源程序17.7所示。
//源程序17.7
<!DOCTYPE HTML PUBLIC”-//W3C//DTD HTML 4.0//EN”
"http://www.w3.org/TR/REC-html140/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Ajax定时刷新页面实例!</title>
</head>
<script language="JavaScript" type="text/javascript">
<!--
//创建函数
function createXMLHTTP()
{
var request;
var browser = navigator.appName;
//使用IE,则使用XMLHTTP对象
if(browser == "Microsoft Internet Explorer")
{
var arrVersions = ["Microsoft.XMLHttp", "MSXML2.XMLHttp.4.0",
"MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp","MSXML2.XMLHttp.5.0"];
for (var i=0; i < arrVersions.length; i++)
{
try
{
//从中找到一个支持的版本并建立XMLHTTP对象
request = new ActiveXObject(arrVersions[i]);
return request;
}
catch (exception)
{
//忽略,继续
}
}
}
else
{
//否则返回一个XMLHttpRequest对象
request = new XMLHttpRequest();
if(request.overrideMimeType)
{
request.overrideMimeType('text/xml');
}
return request;
}
}
var http_request = createXMLHTTP();
//请求函数
function makeRequest(url)
{
http_request.open('GET', url, true);
http_request.onreadystatechange = processRequest;
//禁止IE缓存
http_request.setRequestHeader("If-Modified-Since","0");
//发送数据
http_request.send(null);
//每60秒刷新一次页面
setTimeout("makeRequest('"+url+"')", 60000);
}
//处理响应
function processRequest()
{
if(http_request.readyState == 4)
{
if(http_request.status == 0 || http_request.status == 200)
{
var result = http_request.responseText;
if(result=="")
{
result = "系统时间获取失败";
}
document.getElementById ("sysTimeShow").innerHTML="系统时间:"+result;
}
//http_request.status != 200
else
{
alert("请求失败!");
}
}
}
-->
</script>
<body onload="makeRequest('getSystemTime.jsp')">
<center>
<form name="dateForm">
<table>
<tr>
<td align="center"><h2>一分钟刷新一次</h2></td>
</tr>
<tr>
<td><hr></td>
</tr>
<tr>
<td colspan="2" align="center"><div id="sysTimeShow"></div> </td>
</tr>
</table>
</form>
</center>
</body>
</html>
服务器端页面“getSystemTime.jsp”用于获得当前系统时间,其代码如源程序17.8所示。
//源程序17.8
<%@ page language="java"%>
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.util.Date"%>
<%@ page import="java.sql.Timestamp"%>
<%@ page import="java.io.IOException"%>
<%
Date d = new Date();
Timestamp ts = new Timestamp(d.getTime());
String result = ts.toString().substring(0,16);
out.write(result,0,result.length());
%>
把上述两个文件放置在JSP服务器的webapps目录下,使用浏览器载入后,结果页面如图17.17所示。
间隔一分钟后,无须手动刷新,页面自动更新,如图17.18所示。

图17.17 Ajax自动更新实例 图17.18 间隔一分钟自动更新
使用Ajax自动更新内容,无须重载整个页面,只需动态地更新在服务器端已被更新的内容,在加快更新速度的同时,页面更新过程在用户不知不觉的情况下进行,其间用户可以进行其他操作,提供了很好的用户体验。
17.6.9
小结
本节从Ajax的简单框架入手,并配合一个简单的“Hello,Ajax”程序,介绍了Ajax程序的架构,带领读者进入Ajax之门;同时,本节通过三个经典的Ajax实例程序详细介绍了Ajax在三种经典场景的应用,通过实例说话,帮助读者基本掌握Ajax开发技术。
注意:本节中所有测试实例都在JDK 1.5.0与Tomcat 5.0中调试通过,浏览器中输入的地址,如http://localhost:8080/tree.jsp,都是基于程序是放在Tomcat服务器webapps目录下的。如果读者使用不同的环境,或者建立不同的文件夹,配置或者路径均需要做相应的改变。






