专题:Ajax
什么是Ajax
Ajax (Asynchronous JavaScript and XML)不是一个新的技术,事实上,它是一些旧有的成熟的技术以一种全新的更加强大的方式整合在一起。
Ajax的关键技术
u 使用XHTML(HTML)和CSS构建标准化的展示层
u 使用DOM进行动态显示和交互
u 使用XML和XSLT进行数据交换和操纵
u 使用XMLHttpRequest异步获取数据
u 使用JavaScript将所有元素绑定在一起
常见的Ajax成功应用示例
u BACKBASE购物网站
u Google Suggest
u Google Map
Ajax的主要作用
u 改善表单验证方式,不再需要打开新页面,也不再需要将整个页面数据提交
u 不需刷新页面就可改变页面内容,减少用户等待时间 。
u 按需获取数据,每次只从服务器端获取需要的数据 。
u 读取外部数据,进行数据处理整合 。
u 异步与服务器进行交互,在交互过程中用户无需等待,仍可继续操作
Ajax思维方式
我们就通过用户名校验这个简单的例子来看看传统Web应用和AJAX应用开发思维的不同之处。
l 这个最简单的例子需求如下:用户在页面的文本框中输入想注册的用户名,然后点击校验按钮,如果输入的用户名为“wangxingkui”,则提示用户名已经存在,请重新输入,否则提示用户名尚未存在,可以使用此用户名进行注册。
l 传统方式处理:
对于校验用户名的需求,我们需要一个html页面和一个servlet程序。Html页面中包含文本框和提交按钮,他们位于一个form表单中,这个表单将请求提交给servlet程序,servlet程序判断当前的用户名是否是“wangxingkui”,并给出相应的提示,同时servlet中还生成一个链接,用于返回html页面。
l 从这个例子我们可以看到,传统Web开发思维模式的一个特点是通过form表单提交请求信息,然后转向一个新的页面处理请求,并显示服务器端返回的信息。
l 你可以尝试运行一下这些代码,你会发现作为用户的你经历了:在浏览器中输入用户名->点击按钮提交用户名给Servlet->浏览器转向Servlet的页面->等待Servlet处理->Servlet返回响应信息->浏览器中看到Servlet页面的响应信息,当然这其中有几个过程可能时间短暂到你没有注意,但这些过程是确实存在。
l Ajax方式处理:
l Html页面中包含文本框和校验按钮,点击提交按钮以后,我需要通过javascript获取文本框中的数据,然后通过XMLHttprequest发送数据给servlet,此外还需要准备用于接收响应的javascript函数,接收到servlet的提示信息后,我需要将这些信息动态的写在页面上。servlet程序判断当前的用户名是否是“wangxingkui”,并给出相应的提示。
l 注意,AJAX模式下问题分析的方式已经发生了变化:
l servlet不需要返回html页面的链接了,因为我们不需要跳转到servlet表示的页面中,我们只需要获得servlet页面产生的结果
l html页面中我不用表单提交数据了,我的数据通过javascript来获取,然后通过一个叫做XMLHttprequest的对象发送个servlet。而且我没有做页面跳转
l 我需要一个接收servlet响应信息的javascript函数,我没有进入servelt代表的页面查看响应信息,而是把servlet的响应信息接收回来,再显示在我当前的页面上。
l 与传统Web应用模式的流程相比,AJAX应用模式的流程的不同之处
l 当你运行上面的程序,你会发现从用户的角度来看,与传统Web应用模式的流程相比,AJAX应用模式的流程是不同的。
l AJAX应用的流程是:在浏览器中输入数据->点击按钮提交请求->用户可以继续做其他事情;Servlet在处理数据,并发回数据->浏览器收到响应->浏览器中的当前页面显示响应结果,这其中仍然有些过程由于时间短暂使你忽略了它的错在,但实际上这些过程都是存在的。
l 两个流程的对比让我们看到的显而易见的差别就是AJAX应用中没有向新页面跳转,用户不需要处于无事可做的等待中。
传统web应用方式:
在传统的Web应用模型下,大部分的用户操作都会发送一个HTTP请求给服务器,然后服务器开始处理(接收数据,执行业务逻辑,访问数据库等),最后向浏览器返回HTML页面。当服务器处理请求时,用户能够做什么呢?只有等待!
Ajax应用方式
Ajax应用通过在用户和服务器之间引入一个媒介(Ajax engine)来异步发送请求,消除了传统的发送请求-等待-发送请求-等待的特性,极大的提高了用户体验。
两种方式的比较
JavaScript简介
注释
u 单行注释(双斜杠):
// line1
u 多行注释:
/* line1
line2 */
u HTML风格注释(不推荐使用):
<!-- line1
注意,不需要以“-->”来结束
变量
u JavaScript不要求在声明变量时必须明确指出其数据类型(所以称JavaScript为弱类型语言),可以使用统一的关键字var进行声明:
n varage = 33;
n mood= “happy”;
u 但是提前对变量做出声明是一种良好的编程习惯
u 变量名允许包含字母、数字、美元符号($)和下划线字符,但不允许包括空格或标点符号
数据类型
u JavaScript变量的类型是由变量的值决定的,可以对同一个变量赋予不同数据类型的值:
n varage = “thirty three”;
n age= 33;
u JavaScript中重要的数据类型:
n 未定义(undefined),变量未定义
n 空(null),变量未初始化
n 字符串(string),可以放在单引号或双引号中
n 数值(number),可以表示整数、浮点数
n 布尔型(boolean),true或false
n 对象(object)
数组
n 数组用来存储一组值,使用关键字Array来声明,声明时可以指明数组的长度:
n varcolors = new Array();
n varcolors = new Array(3);
n 其中new关键字可以省略,类似其它语言,数组的下标从0开始,赋值方法也和其它语言类似:
n colors[0]= “red”;
n colors[1]= “black”;
n colors[2]= “white”;
n 还可以使用方括号创建数组时同时初始化:
n varcolors = [“red”, “black”, “white”];
n 使用方括号创建数组对象的简单方法:
n varcolors = [ ]; //声明空数组对象
n colors[0]= “red”;
n colors[1]= “black”;
n 通过数组的length属性可以得到数组中元素的个数。数组的长度可以动态扩展:
n colors[3]= “blue”;
n colors[8]= “grey”;
n 关联数组:在填充数组时为每个新元素明确地给出下标:
n colors[“r”]= “red”;
n colors[“b”]= “black”;
运算符
n JavaScript中的算术运算符(+、-、*、/、++、--等)、比较运算符(>、<、=、<=、>=)、条件语句(if、while、for等)
函数
n 使用函数可以避免重复输入大量相同的内容。JavaScript中使用function关键字定义函数:
n function funcname (arg1, arg2, …) {
statements;
}
n 声明一个简单的函数:
n function multiply (num1, num2) {
vartotal = num1 * num2;
returntotal;
}
声明后可以直接调用此函数获取结果:
var result = multiply(5, 9);
注意,JavaScript中的函数不需声明返回类型,参数也不需要声明类型
对象
n JavaScript对象是由一组相关的属性和方法构成的数据实体。属性和方法都要使用“.”来访问:
n object.property
n object.method()
n 使用函数来定义“类”:
n functionPerson() {
this.age = 12;
this.name = “no name”;
this.sayHello = function() {
alert(“Hello” + this.name); //其中this关键字不能省略!
}
}
n 使用new关键字来创建对象实例:
n varvincent = new Person();
DOM基础
DOM简介
n DOM是”DocumentObject Model”(文档对象模型)的首字母缩写。当创建了一个网页并把它加载到Web浏览器中时,就会在幕后创建一个文档对象模型。
n DOM表示被加载到浏览器窗口里的当前页面:浏览器向我们提供了当前页面的模型,而我们可以通过JavaScript访问这个模型。
n DOM把一份文档表示为一棵树。
例如有如下html文档:
<html>
<head>
<title>Trees, tress,everywhere</title>
</head>
<body>
<h1>Tress, tress,everywhere</h1>
<p>Welcome to a<em>really</em>boring page.</p>
<div>
Come again soon.
<imgsrc="come-again.gif" />
</div>
</body>
</html>
浏览器加载该页面并将之转换为树形结构
n DOM树中的一切是以最外层的HTML包含元素,即html元素开始的。使用树的比喻,这叫做根元素(rootelement)。
n 从根流出的线表示不同标记部分之间的关系。head和body元素是html根元素的孩子(child);title是head的孩子,而文本 “Trees,trees, everywhere”是title的孩子;相对的,head是title的父亲(parent),title是文本 “Trees,trees, everywhere” 的父亲。处在同一层次的且互不包含的两个分支(如head和body)之间称为兄弟(sibling)关系。整个树就这样组织下去,直到浏览器获得与上图类似的结构。
n 通常把这样的树结构成为一棵节点树。
节点node
u DOM文档是由节点构成的集合,此时的节点是文档树上的树枝或者树叶。
u DOM中节点的类型:
n 元素节点(elementnode),诸如<head>、<p>、<div>等。元素节点可以包含其它的元素,唯一没有被包含在其它元素里的元素是<html>,它是根元素。
n 属性节点(attributenode),元素或多或少地有一些属性,属性可以对元素做出一些具体的描述。因为属性总是被放到起始标签里,所以属性节点总是被包含在元素节点中。
n 文本节点(textnode),<h1>元素中包含着文本节点“Trees,trees, everywhere”。
基本DOM方法
n getElementById(id)
n 返回一个给定id属性的元素节点相对应的对象。这个方法是与document对象相关联的函数。其中document对象代表着整个HTML文档并可以用来访问所有页面中的元素。
n getElementsByTagName(tagname)
n 返回一个对象数组,它们分别对应着文档里的一个特定的元素节点。
n getAttribute()
n 返回对象的属性值
n setAttribute()
n 修改对象的属性值
重要DOM属性
n childNodes
n 可以将节点树中任何一个元素的所有子元素检索出来,这个属性返回一个数组,包含了给定元素节点的全体子元素。
n nodeName
n 返回元素节点的名称。注意,返回的结果全部是大写。
n nodeType
n 用来区分节点的类型,元素节点的nodeType属性值是1,属性节点的nodeType属性值是2,文本节点的nodeType属性值是3。
n nodeValue
n 可以用来存取文本节点的值。对于元素节点或属性节点这个属性返回空。
n firstChild和lastChild
n 第一个和最后一个孩子节点。
node.firstChild等价于node.childNodes[0],
node.lastChild等价于node.childNodes[node.childNodes.length–1]
n parentNode
n 返回元素的父节点
n nextSibling
n 返回下一个兄弟节点
改变网页结构的DOM方法
n createElement(tagname)
n 创建新的元素节点,此方法与document对象相关联。新建的元素节点并未与节点树相连。
n appendChild(node)
n 把新建的节点插入到节点树的某个节点下,成为这个节点的子节点。
n createTextNode(text)
n 创建文本节点
n insertBefore(newNode,targetNode)
n 把一个新元素插入到一个现有元素的前面
n replaceChild(newChild,oldChild)
n 替换一个孩子节点
n removeChild(node)
n 删除一个孩子节点
第一个AJAX示例
总结:AJAX应用的五个步骤
1、 创建XMLHttpRequest对象
2、 设置回调函数
3、 使用open方法与服务器建立链接
4、 向服务器端发送数据
5、 在回调函数针对不同响应状态进行处理
需要注意的内容:
1.不同浏览器下XMLHttpRequest对象的不同的建立方式
2.设置回调函数时不要加括号
3. open方法三个参数含义,此外还需要注意GET方式和POST方式服务器端地址的不同写法
4. GET方式和POST方式send的参数的不同之处,以及POST方式下send之前需要设置请求头信息的工作
5.如何判断正确的响应数据已经返回,此外还要注意如何获取响应数据内容。
//index.html
<!DOCTYPEHTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>index.html:ajax 检验</title>
<metahttp-equiv="keywords"content="keyword1,keyword2,keyword3">
<metahttp-equiv="description"content="this is my page">
<metahttp-equiv="content-type"content="text/html; charset=gb18030">
<scripttype="text/javascript"src="jslib/verifyOwn.js"></script>
</head>
<body>
用ajax进行检验!<br>
<inputtype="text"id="username"/>
<inputtype="button"value="检验"onclick="verify()"/>
<divid="result"></div>
</body>
</html>
//AJAXServer.java
publicclassAJAXServer extends HttpServlet {
protectedvoiddoPost(HttpServletRequest httpServletRequest,
HttpServletResponsehttpServletResponse)throws ServletException,
IOException {
doGet(httpServletRequest,httpServletResponse);
}
protectedvoid doGet(HttpServletRequesthttpServletRequest,
HttpServletResponsehttpServletResponse)throws ServletException,IOException{
try {
//request.setCharacterEncoding("UTF-8");
//response.setContentType("text/html;charset=gb18030");
httpServletResponse.setContentType("text/html;charset=utf-8");
PrintWriter out =httpServletResponse.getWriter();
Integer inte = (Integer)httpServletRequest.getSession()
.getAttribute("total");
int temp = 0;
if (inte ==null) {temp = 1; }
else {temp = inte.intValue() + 1; }
httpServletRequest.getSession().setAttribute("total", temp);
// 1.取参数
String old =httpServletRequest.getParameter("name");
// String name = newString(old.getBytes("iso8859-1"),"UTF-8");
String name = URLDecoder.decode(old,"UTF-8");
// 2.检查参数是否有问题
if (old ==null || old.length() == 0){
out.println("用户名不能为空");
} else {
// String name =URLDecoder.decode(old,"UTF-8");
// byte[] by =old.getBytes("ISO8859-1");
// String name = newString(by,"utf-8");
// String name =URLDecoder.decode(old,"utf-8");
// 3.校验操作
// String name = old;
if (name.equals("wangxingkui")) {
// 4。和传统应用不同之处。这一步需要将用户感兴趣的数据返回给页面段,而不是将一个新的页面发送给用户
// 写法没有变化,本质发生了改变
out.println("用户名[" + name + "]已经存在,请使用其他用户名, " + temp);
}else {
out.println("用户名[" + name + "]尚未存在,可以使用该用户名注册, " + temp);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 自定义的verifyOwn.js
var xmlhttp;
function verify() {
//从文本框取数据
var username = document.getElementById("username").value;
// 1.创建XMLHttpRequest对象
if (window.XMLHttpRequest) {
xmlhttp =new XMLHttpRequest();
if (xmlhttp.overrideMineType) {
xmlhttp.overrideMineType("text/xml");
}
} elseif (window.ActiveXObject) {
var activeName = ["MSXML2.XMLHTTP","Microsoft.XMLHTTP" ];
for (var i = 0; i < activeName.length; i++){
try {
xmlhttp =newActiveXObject[activeName[i]];
break;
} catch (e) {
}
}
}
if (!xmlhttp) {
// alert("XMLHttpRequest对象创建失败!")
return;
} else {
// alert(xmlhttp.readyState);
}
// 2.注册回调函数
xmlhttp.onreadystatechange =callback;
// 3.设置联接信息
// get方式
// xmlhttp.open("GET","AJAXServer?name=" +username, true);
// post方式
xmlhttp.open("POST","AJAXServer",true);
xmlhttp.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
xmlhttp.send("name=" + username);
// 4.发送数据,并和服务器端进行交付
// xmlhttp.send(null);
}
function callback() {
// 5.接收响应数据
// alert(xmlhttp.readySrate);
if (xmlhttp.readyState == 4) {
if (xmlhttp.status == 200) {
varresponseText = xmlhttp.responseText;
var divNode =document.getElementById("result");
divNode.innerHTML =responseText;
} else {
alert("出错了!");
}
}
}
注意,
u“window.XMLHttpRequest”为true时表示当前浏览器是IE7,IE8,Moxilla或其他浏览器,我们就可以使用new XMLHttpRequest()的方式来创建一个XMLHttpRequest对象
lif(xmlhttp.overrideMimetype)这个逻辑的作用是解决部分版本的Mozilla在服务器响应头信息没有XML时不能正常工作的问题。
u“window.ActiveXObject”为true时表示当前的浏览器为IE6.0及以下的版本,要使用new ActiveXObject(控件名)的方式来创建一个XMLHttpRequest对象
u这里需要注意的是不同版本IE中用于建立XMLHttpRequest对象的控件版本很多。如果使用MSXML数组中的某一个控件名称成功建立了XMLHttpRequest对象,则跳出循环,如果建立失败会有异常抛出,被catch以后继续进行循环,尝试下一个控件名称。这里的控件名称是按照从新到老的顺序排列的,这样可以保证使用较新版本IE的用户可以较早成功建立XMLHttpRequest对象。如果没有建立成功XMLHttpRequest对象,则不能继续后面与服务器端交互的工作,函数只能返回。
u然后设置回调函数。设置回调函数时只给出回调函数的名称,后面不要带括号,因为带上括号就变成让XMLHttpRequest对象的onreadystatechange属性值等于回调函数的返回值了。
u接下来要做的工作是建立对服务器的调用。这里第一个参数表示http连接的方法, 一般我们使用“GET”或“POST”方式。第二个参数是服务器端地址,由于使用GET方式,因此要传送给服务器端的数据也在URL中,这里我们使用了两个encodeURI,目的是为了解决URL中的中文信息在服务器端解码的问题,配合服务器端的URLDecoder.decode(old,“UTF-8”)语句可以保证中文信息在服务器端也可以正常被解出。第三个参数表示是否采用异步方式进行传输,其中true表示采用异步方式,我们在AJAX中看重的就是异步方式,因此这个参数我们通常使用true。
u这里readyState=4时表示服务器端的响应数据已经被全部接收,readyState还有其他状态,0=未初始化。1=open方法成功调用以后。2=服务器已经应答客户端的请求。3=交互中。即Http头信息已经接收,响应数据尚未接收。4=完成。数据接收完成。
uStatus=200表示http连接状态正常,如果不是200,则表示http连接有误,此时回来的数据也不是我们需要的。
u当响应数据全部接收并且http连接状态正确时,我们就可以接收响应的数据了,这里使用了xmlhttp.responseText用于以文本形式接收响应的数据,当然也可以用XML方式接收,后面会做详细介绍。