Ajax
1. XMLHttpRequest对象
XMLHttpRequest对象在Ajax中占据着十分重要的地位,Ajax中的客户端就是通过XMLHttpRequest对象实现与服务器通信的。
1.1 创建XMLHttpRequest对象
此对象需要在发送请求和接收响应之前创建。在IE浏览器中,XMLHttpRequest对象是以ActiveX组件的形式提供的;而在其他浏览器中则使用JavaScript的本地方法来创建。所以在创建XMLHttpRequest对象的时候,需要对此差别进行对应的判断和处理。下面的代码就是创建XMLHttpRequest对象的通用代码。
var XMLHttpReq;
//创建XMLHttpReques对象
function createXMLHttpRequest(){
if (window.XMLHttpRequest) {
//Mozilla 浏览器
XMLHttpReq = new XMLHttpRequest();
} else {
// IE浏览器
if (window.ActiveXObject) {
try {
XMLHttpReq = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
XMLHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
}
}
}
}
}
在上面这个JavaScript函数中,实现的功能是创建一个XMLHttpRequest对象,其中window.XMLHttpRequest可以用来判断浏览器是否通过JavaScript本地方法支持XMLHttpRequest对象,如果是,就可以用下面的方法创建这个对象,这就是除IE浏览器外其他浏览器中创建XMLHttpRequest对象的方法。
XMLHttpReq = newXMLHttpRequest();
用window.ActiveXObject可以判断浏览器是否支持ActiveX,在IE浏览器中是通过ActiveX组件来支持XMLHttpRequest对象的,如果浏览器支持ActiveX,就可以使用下面的方法创建XMLHttpRequest对象,这就是在IE浏览器中创建XMLHttpRequest对象的方法。
try {
XMLHttpReq= new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try{
XMLHttpReq= new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
}
}
在不同版本的IE浏览器中,对XMLHttpRequest对象的支持方法有些不同,可以通过上面这样判断来适应不同版本的IE浏览器。
1.2 XMLHttpRequest常用方法和属性
在XMLHttpRequest对象创建以后,就可以对这个对象进行各种不同的操作,从而完成和服务器的通信。
open(stringmethod,string url,boolean asynch,string name,string password)和send(content)是XMLHttpRequest对象中最常用的方法。
open(stringmethod,string url,boolean asynch,string name,string password)方法可以建立对服务器的调用,共有5个参数,前两个参数是必需的。其中method可以是GET或者POST,url是指所要访问的服务器资源的位置,asynch是指异步访问服务器还是同步访问,默认是异步访问,异步访问正是Ajax的优势所在。使用最后两个参数可以使用指定的用户名和密码访问服务器资源。
send(content)方法可以向服务器发送请求,此方法中的参数会作为请求中的内容发送到服务器。
在XMLHttpRequest对象中,可以通过一系列的属性访问这个对象的具体参数,下面是一些常用的属性。
readyState属性描述了请求的状态。可以取下面的5个值:0(未初始化)、1(正在加载)、2(已加载)、3(交互中)、和4(已完成)。
onreadystatechange属性,每个状态的改变都会调用这个事件处理器,使用这个属性可以监听状态的变化,并提供对应的处理方法。
status属性描述了服务器的状态码,可以是200、404等。
statusText描述了HTTP状态码对应的文本,例如200对应OK、404对应Not Found。
responseText是服务器以文本字符串返回的响应。
responseXML是服务器以XML格式返回的响应。
使用上面这些基本的方法和属性,就可以使用XMLHttpResponse对象的基本功能。
1.3 客户端向服务器发送请求
在Ajax中,向服务器端发送请求使用的是XMLHttpRequest对象,在XMLHttpRequest对象成功创建以后,就可以通过这个对象与服务器进行通信。
1.3.1 使用XMLHttpRequest对象发送请求
在向服务器发送请求之前,首先使用XMLHttpRequest对象的open(stringmethod,string url,boolean asynch,string name,string password)方法建立对服务器的调用,然后才能向服务器发送请求信息。而且在这里还需要指明在请求状态发生改变的时候需要调用的响应处理方法。
在成功创建XMLHttpRequest对象以后,可以使用下面这个JavaScript函数向服务器发送请求。
//发送客户端的请求
function sendRequest(url){
createXMLHttpRequest();
XMLHttpReq.open("GET", url, true);
//指定响应函数
XMLHttpReq.onreadystatechange = handleResponse;
// 发送请求
XMLHttpReq.send(null);
}
url是要访问服务器资源的位置。
handleResponse是用户自己实现的一个处理服务器响应内容的JavaScript函数。在Ajax中,一般情况下都会实现一个JavaScript函数来处理请求状态变化的事件。
1.3.2 常用发送请求内容的方法
在传统的Web应用中,需要通过表单向服务器提交用户的输入信息,但是这种方式会刷新整个页面,而在Ajax中要实现的就是与服务器的异步通信,所以不能使用表单向服务器发送请求信息,可以使用下面几种方法来向服务器发送请求的内容。
当请求的内容比较少时,例如仅仅是有限的几个参数,就可以使用显式传参的方式。例如(http://localhost:8080/ajax/sayHello?name=rain&password=123)在整个URL中,访问的是sayHello这个Servlet,而且建立服务器调用的同时向sayHello这个Servlet传递了一个参数,其中参数name的值为rain,参数password的值为123。这种传值方式和一般Web页面中通过超链接传值方式的原理是一样的。在使用这种方式向服务器发送信息的时候,send(content)中的参数就可以用null代替。
但是当向服务器发送的内容比较多,而且格式比较复杂时,使用超链接的方式就现实了。在这种情况下,可以把要发送的内容组织成XML文档,然后通过send(content)就可以把参数的内容发送到服务器,其中content参数就是XML文档的内容。
此外,也可以使用send方法传递参数。使用send方法传递参数使用的是POST方法,需要设定Content-Type头信息,模拟HTTP POST方法发送一个表单,这样服务器才会知道如何处理上传的内容。参数的提交格式和GET方法中url的写法一样。设置头信息前必须先调用open方法。
xmlHttpRequest.open("POST","login.jsp",true);
xmlHttpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");
xmlHttpRequest.send("user="+username+"&pwd="+password);
需要注意的是根据提交方式的不同,两种提交方式分别调用后台的doGet方法和doPost方法。
总之,在客户端向服务器发送请求内容的方法是多种多样的,并不局限于上面这两种,可以自己规定发送内容的格式,然后通过send方法发送给服务器,在服务器端处理请求信息时,用同样的格式规则把请求的内容解析出来。
1.4 服务器端处理用户请求
在Ajax中,服务器接收到用户的请求以后,可以根据请求的内容进行相应的操作,然后把操作以合适的格式返回给客户端。
服务器端的处理方式有多种选择,可以选择JSP、ASP、CGI或Servlet的任意一种作为相应客户端请求的服务程。
1.4.1 在服务端处理用户请求
由于客户端向服务器发送信息的时候,可以选择多种上方式进行发送,所以服务器端就需要根据客户端发送信息的方式,对接收到的信息进行分析,从而取出进一步操作所需要的信息。
当客户端使用超链接传递参数的时候,服务器端的处理就比较简单,仅仅通过request.getParameter(“参数名称”)就可以取出对应参数的值,然后根据取得的值进行相应的逻辑操作。
当客户端使用XML格式发送请求信息的时候,在服务器端就需要对接收到的XML文档进行分析,可以使用DOM或者SAX从这个XML文档中取出需要的信息,然后才能进行相应的逻辑操作。在解析XML文档的时候有很多成熟的XML解析器可供选择。
当客户端使用自定义的格式发送请求信息的时候,服务器端需要根据信息的格式来解析接收到的请求,取出所需的值以后才能进行进一步的逻辑操作。
1.4.2 返回XML格式的响应文档
在服务器端完成用户需要的逻辑处理以后,需要把处理的结果返回给用户,在这种情况下,一般是把处理的结果组织成XML的格式,然后把这个XML文档返回给客户端。
本例通过Servlet处理客户端的请求,在Servlet中可以完成对用户请求的处理,然后通过Servlet把处理的结果以XML的格式返回给客户端。
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
// 设置生成文件的类型和编码格式
response.setContentType("text/xml;charset=UTF-8");
response.setHeader("Cache-Control","no-cache");
PrintWriter out = response.getWriter();
String output = "";
// 处理接收到的参数,生成响应的XML文档
if (request.getParameter("name")!= null
&& request.getParameter("name").length()> 0)
output = "<response>Hello" + request.getParameter("name")
+ "</response>";
out.println(output);
out.close();
}
XML文档的内容可以根据用户的需要生成,然后把生成的内容放在PrintWriter对象中返回给用户即可。
1.5 客户端处理服务器响应
当服务器端结束对用户请求的处理以后,会把处理的结果返回给用户,在客户端对返回的内容进行处理,然后根据其处理结果对页面的内容进行调整,到这一步为止,客户端与服务器端的异步通信就未完成了。
1.5.1 分析XML格式的文档
在一般情况下,服务器会用XML文档返回逻辑处理的结果,在客户端可以通过XMLHttpRequest对象取得这个响应文档的内容。在Javascript中,可以用DOM方式分析这个XML文档,这种分析方法和一般的XML文档的分析方法是完全相同的。
通过XMLHttpRequest对象的responseXML属性取出服务器返回的响应文档,然后就可以使用Javascript对这个文档进行分析,从而取出用户需要的内容。
1.5.2 使用Javascript调整页面内容
在对XML文档解析结束以后,就可以根据解析的结果来调整页面的内容,从而把服务器的处理结果表现在页面上。通常情况下会使用Javascript来完成这个任务,通过使用innerText或者innerHTML可以设置HTML页面元素内的显示内容;通过DOM操作,可以动态创建HTML元素;通过CSS可以控制页面HTML元素的显示风格。通过这些操作,可以把服务器返回的处理结果充分展现在页面上,从而最终完成客户端和服务器的异步通信,而且这种处理方式是不会对整个页面进行刷新的。
1.5.3 客户端处理服务器响应的示例代码
//处理服务器响应结果
function handleResponse(){
// 判断对象状态
if (XMLHttpReq.readyState == 4) {
// 信息已经成功返回,开始处理信息
if (XMLHttpReq.status == 200) {
var out = "";
var res = XMLHttpReq.responseXML;
var response = res.getElementsByTagName("response")[0].firstChild.nodeValue;
document.getElementById("hello").innerHTML= response;
}
}
}
在上面这个Javascript函数中,对服务器返回的信息进行了分析处理,并且把分析的结果展现在页面的指定位置。其中当XMLHttpRequest的“readyState”属性为“4”的时候说明请求的处理已经完成,当XMLHttpRequest对象的“status”属性为“200”的时候,说明服务器的处理信息已经成功返回,这个时候可以开始取出返回的信息,然后进行分析处理。
取出服务器响应文档的时候,可以使用XMLHttpRequest对象的responseXML属性,在取出XML响应文档以后,就可以使用Javascript通过DOM的方式来解析这个文档,然后把解析的结果展示在HTML页面中。
2. Ajax典型示例
2.1 异步身份验证
在传统的Web应用中,用户的身份验证是通过向服务器提供表单实现的,服务器对表单中的用户信息进行验证,然后再返回验证的结果。在这样的处理方式中,客户端必须等到服务器返回处理结果后才能进行其他的操作,而且在这个过程中,会刷新整个页面。这种处理方式不仅浪费了用户的时间,每次刷新页面也浪费了巨大的带宽。
针对上面这种情况,可以采用Ajax的方式进行处理。在Ajax的处理方式的,可以把用户的信息通过XMLHttpRequest对象异步发送给服务器,在服务器端完成对用户的身份验证以后,会把处理的结果通过XMLHttpRequest对象返回给用户,从而以异步的方式,在不刷新整个页面的情况下完成对用户的身份验证。
2.1.1 验证页面代码
<%@ page language="java"import="java.util.*" pageEncoding="gb2312"%>
<html>
<head>
<title>异步身份验证</title>
<script language="javascript">
//创建XMLHttpReques对象
function createXMLHttpRequest(){
if (window.XMLHttpRequest) {
//Mozilla 浏览器
XMLHttpReq = new XMLHttpRequest();
} else {
// IE浏览器
if (window.ActiveXObject) {
try {
XMLHttpReq = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
XMLHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
}
}
}
}
}
//处理服务器响应结果
function handleResponse(){
// 判断对象状态
if (XMLHttpReq.readyState == 4) {
// 信息已经成功返回,开始处理信息
if (XMLHttpReq.status == 200) {
var out = "";
var res = XMLHttpReq.responseXML;
var response = res.getElementsByTagName("response")[0].firstChild.nodeValue;
document.getElementById("result").innerHTML= response;
}
}
}
//发送客户端的请求
function sendRequest(url,data) {
createXMLHttpRequest();
XMLHttpReq.open("POST", url, true);
XMLHttpReq.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
//指定响应函数
XMLHttpReq.onreadystatechange = handleResponse;
// 发送请求
XMLHttpReq.send(data);
}
//开始调用Ajax的功能
function userCheck() {
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
//发送请求
sendRequest("${pageContext.request.contextPath}/UserCheck","username="
+ username + "&password="+ password);
}
</script>
</head>
<body>
<table>
<tr>
<td>
用户名:
</td>
<td>
<input type="text"name="username" />
</td>
</tr>
<tr>
<td>
密码:
</td>
<td>
<input type="password"name="password" />
</td>
</tr>
<tr>
<td colspan="2">
<div id="result"></div>
</td>
</tr>
<tr>
<td colspan="2">
<input type="button"value="提交" οnclick="userCheck()" />
</td>
</tr>
</table>
</body>
</html>
2.1.2 Servlet代码
importjava.io.IOException;
importjava.io.PrintWriter;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
public class UserCheckextends HttpServlet {
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
// 设置生成文件的类型和编码格式
response.setContentType("text/xml;charset=UTF-8");
response.setHeader("Cache-Control","no-cache");
PrintWriter out = response.getWriter();
String output = "";
// 处理接收到的参数,生成响应的XML文档
String username = request.getParameter("username");
String password = request.getParameter("password");
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
// 下面对用户的身份进行判断
if (username.equals("sa")&& password.equals("123"))
output = "<response>通过验证、是有效用户。</response>";
else
output = "<response>用户名或者密码错误。</response>";
out.println(output);
out.close();
}
}
2.2 输入提示和自动完成
若使用Google搜索或百度搜索,则在输入搜索关键字的同时,会自动弹出与输入的关键字相匹配的其他关键字的提示。这种输入提示和自动完成的功能是Google首先推出的,然后在各种Web应用中被广泛采用。
2.2.1 页面代码
<%@ page language="java"import="java.util.*" pageEncoding="gb2312"%>
<html>
<head>
<title>输入提示示例</title>
<style>
TD {
FONT-SIZE: 12px
}
</style>
<script language="javascript">
//创建XMLHttpReques对象
function createXMLHttpRequest(){
if (window.XMLHttpRequest) {
//Mozilla 浏览器
XMLHttpReq = new XMLHttpRequest();
} else {
// IE浏览器
if (window.ActiveXObject) {
try {
XMLHttpReq = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
XMLHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
}
}
}
}
}
//处理服务器响应结果
function handleResponse(){
// 判断对象状态
if (XMLHttpReq.readyState == 4) {
// 信息已经成功返回,开始处理信息
if (XMLHttpReq.status == 200) {
clearTable();
var out = "";
var res = XMLHttpReq.responseXML;
var items = res.getElementsByTagName("item");
for ( var i = 0; i < items.length; i++){
addRow(items(i).firstChild.nodeValue);
}
setDivStyle();
}
}
}
//清除表格中的结果
function clearTable(){
var content = document.getElementById("content");
while (content.childNodes.length > 0) {
content.removeChild(content.childNodes[0]);
}
}
//向输入提示的表格中添加一行记录
function addRow(item){
var content = document.getElementById("content");
var row = document.createElement("tr");
var cell = document.createElement("td");
cell.appendChild(document.createTextNode(item));
cell.onmouseover = function() {
this.style.background = "blue"
};
cell.onmouseout = function() {
this.style.background = "#f5f5f1"
};
cell.onclick = function() {
document.getElementById("key").value= this.innerHTML;
document.getElementById("suggest").style.visibility= "hidden"
};
row.appendChild(cell);
content.appendChild(row);
}
//发送客户端的请求
function sendRequest(url,data) {
createXMLHttpRequest();
XMLHttpReq.open("POST", url, true);
XMLHttpReq.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
//指定响应函数
XMLHttpReq.onreadystatechange = handleResponse;
// 发送请求
XMLHttpReq.send(data);
}
//调用Ajax自动提示功能
function suggest() {
var key = document.getElementById("key").value;
sendRequest("${pageContext.request.contextPath}/Suggest","key="+ key);
}
//设置输入提示框的位置和风格
function setDivStyle(){
var suggest = document.getElementById("suggest");
suggest.style.border = "black 0pxsolid";
suggest.style.left = 82;
suggest.style.top = 50;
suggest.style.width = 152;
suggest.style.backgroundColor = "#f5f5f1"
document.getElementById("suggest").style.visibility= "visible"
}
</script>
</head>
<body>
输入提示示例(可以输入字母a开头的字符串进行测试)
<br>
请输入:
<input type="text" id="key"name="key" οnkeyup="suggest()" />
<div id="suggest" style="position:absolute">
<table>
<tbody id="content"></tbody>
</table>
</div>
</body>
</html>
2.2.2 Servlet代码
importjava.io.IOException;
importjava.io.PrintWriter;
importjava.util.ArrayList;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
public class Suggestextends HttpServlet {
private ArrayList lib = new ArrayList();
// 初始化数据集合,可以在这个字库中添加更多词条
public void init() throws ServletException {
lib.add("a");
lib.add("able");
lib.add("access");
lib.add("advance");
}
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
// 设置生成文件的类型和编码格式
response.setContentType("text/xml;charset=UTF-8");
response.setHeader("Cache-Control","no-cache");
PrintWriter out = response.getWriter();
String output = "";
// 处理接收到的参数
String key = request.getParameter("key");
ArrayList matchList =getMatchString(key);
if (!matchList.isEmpty()) {
output += "<response>";
for (int i = 0; i < matchList.size();i++) {
String match =matchList.get(i).toString();
output += "<item>"+ match + "</item>";
}
output += "</response>";
}
out.println(output);
out.close();
}
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
// 取得所有匹配的字符串
public ArrayList getMatchString(Stringkey) {
ArrayList result = new ArrayList();
if (!lib.isEmpty()) {
for (int i = 0; i < lib.size(); i++){
String str = lib.get(i).toString();
if (str.startsWith(key))
result.add(str);
}
}
return result;
}
}
2.3 自动刷新
使用Ajax可以实现自动刷新的功能,而且是页面的局部刷新,这种刷新方式不会对页面的其他部分造成影响。
2.3.1 页面代码
<%@ page language="java"import="java.util.*" pageEncoding="gb2312"%>
<html>
<head>
<title>自动异步刷新页面</title>
<script language="javascript">
//创建XMLHttpReques对象
function createXMLHttpRequest(){
if (window.XMLHttpRequest) {
//Mozilla 浏览器
XMLHttpReq = new XMLHttpRequest();
} else {
// IE浏览器
if (window.ActiveXObject) {
try {
XMLHttpReq = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
XMLHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
}
}
}
}
}
//处理服务器响应结果
function handleResponse(){
// 判断对象状态
if (XMLHttpReq.readyState == 4) {
// 信息已经成功返回,开始处理信息
if (XMLHttpReq.status == 200) {
var out = "";
var res = XMLHttpReq.responseXML;
var response = res.getElementsByTagName("response")[0].firstChild.nodeValue;
document.getElementById("content").innerHTML= response;
//设置在6000毫秒以后重新从服务器取值
setTimeout("refreshRequest()",6000);
}
}
}
//发送客户端的请求
function sendRequest(url){
createXMLHttpRequest();
XMLHttpReq.open("GET", url, true);
//指定响应函数
XMLHttpReq.onreadystatechange = handleResponse;
// 发送请求
XMLHttpReq.send(null);
}
//开始调用Ajax的功能
function refresh() {
refreshRequest();
//实时刷新页面的倒计时时间
refreshTime();
}
//向服务器发送请求
function refreshRequest(){
sendRequest("Refresh");
}
//实时刷新页面的倒计时时间
function refreshTime(){
setTimeout("refreshTime()", 1000);
var time = document.getElementById("time").innerHTML;
time = time - 1;
if (time > 0) {
document.getElementById("time").innerHTML= time;
} else {
document.getElementById("time").innerHTML= 6;
}
}
</script>
</head>
<body οnlοad="refresh()">
本页面将在
<span id="time"></span>秒中之内刷新局部区域
<br>
<div id="content"></div>
</body>
</html>
2.3.2 Servlet代码
importjava.io.IOException;
importjava.io.PrintWriter;
importjava.util.Date;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
public class Refreshextends HttpServlet {
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
//设置生成文件的类型和编码格式
response.setContentType("text/xml;charset=UTF-8");
response.setHeader("Cache-Control","no-cache");
PrintWriter out = response.getWriter();
String res = "";
String output = "";
//处理接收到的参数,生成响应的XML文档
Date date = new Date();
res += "上次页面刷新时间为:"+date.toLocaleString();
output = "<response>"+res+"</response>";
out.println(output);
out.close();
}
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
}