什么是AjaxAjax(Asynchronous JavaScript and XML) 异步JavaScript和XMLAjax实际上是下面这几种技术的融合:
(1)XHTML和CSS的基于标准的表示技术
(2)DOM进行动态显示和交互
(3)XML和XSLT进行数据交换和处理
(4)XMLHttpRequest进行异步数据检索
(5)Javascript将以上技术融合在一起
客户端与服务器,可以在【不必刷新整个浏览器】的情况下,与服务器进行异步通讯的技术为什么我们需要Ajax?在我们之前的开发,每当用户向服务器发送请求,哪怕只是需要更新一点点的局部内容,服务器都会将整个页面进行刷新。
性能会有所降低(一点内容,刷新整个页面!)
用户的操作页面会中断(整个页面被刷新了)
Ajax就是能够做到局部刷新!XMLHttpRequestXMLHttpRequest对象是Ajax中最重要的一个对象。使用Ajax更多的是编写客户端代码,而不是服务端的代码。XMLHttpRequest 工作原理传统的web前端与后端的交互中,浏览器直接访问Tomcat的Servlet来获取数据。Servlet通过转发把数据发送给浏览器。当我们使用AJAX之后,浏览器是先把请求发送到XMLHttpRequest异步对象之中,异步对象对请求进行封装,然后再与发送给服务器。服务器并不是以转发的方式响应,而是以流的方式把数据返回给浏览器XMLHttpRequest异步对象会不停监听服务器状态的变化,得到服务器返回的数据,就写到浏览器上【因为不是转发的方式,所以是无刷新就能够获取服务器端的数据】创建XMLHttpRequest对象要创建XMLHttpRequest对象是要分两种情况考虑的:
在IE6以下的版本
在IE6以上的版本以及其他内核的浏览器(Mozilla)等
varhttpRequest;
if(window.XMLHttpRequest){
//在IE6以上的版本以及其他内核的浏览器(Mozilla)等
httpRequest=newXMLHttpRequest();
}elseif(window.ActiveXObject){
//在IE6以下的版本
httpRequest=newActiveXObject();
}
了解XMLHttpRequest对象的属性和方法方法
open()(String method,String url,boolean asynch,String username,String password)
send(content)
setRequestHeader(String header,String value)
getAllResponseHeaders()
getResponseHeader(String header)
abort()
常用的方法就是黑色粗体的前三个
open():该方法创建http请求
第一个参数是指定提交方式(post、get)
第二个参数是指定要提交的地址是哪
第三个参数是指定是异步还是同步(true表示异步,false表示同步)
第四和第五参数在http认证的时候会用到。是可选的
setRequestHeader(String header,String value):设置消息头(使用post方式才会使用到,get方法并不需要调用该方法)
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
send(content):发送请求给服务器
如果是get方式,并不需要填写参数,或填写null
如果是post方式,把要提交的参数写上去
属性
onreadystatechange:请求状态改变的事件触发器(readyState变化时会调用此方法),一般用于指定回调函数
readyState:请求状态readyState一改变,回调函数被调用,它有5个状态
0:未初始化
1:open方法成功调用以后
2:服务器已经应答客户端的请求
3:交互中。Http头信息已经接收,响应数据尚未接收。
4:完成。数据接收完成
responseText:服务器返回的文本内容
responseXML:服务器返回的兼容DOM的XML内容
status:服务器返回的状态码
statusText:服务器返回状态码的文本信息
上面有两个地方都提及了回调函数,回调函数是什么??回调函数就是接收服务器返回的内容!编写第一个Ajax程序检测用户输入的用户名是否为"zhongfucheng",只要不是zhongfucheng,就可以使用!html代码
创建的div只要用于显示服务器返回的数据
当用户点击按钮的时候,就触发事件。
JavaScript代码
创建XMLHttpRequest对象
创建http请求
把文本框的数据发送给http请求的目标
指定回调函数
编写回调函数
发送http请求
回调函数得到http返回的内容,把内容写在div上
varhttpRequest;
functioncheckUsername(){
if(window.XMLHttpRequest){
//在IE6以上的版本以及其他内核的浏览器(Mozilla)等
httpRequest=newXMLHttpRequest();
}elseif(window.ActiveXObject){
//在IE6以下的版本
httpRequest=newActiveXObject();
}
//创建http请求
httpRequest.open("POST","Servlet1",true);
//因为我使用的是post方式,所以需要设置消息头
httpRequest.setRequestHeader("Content-type","application/x-www-form-urlencoded");
//指定回调函数
httpRequest.onreadystatechange=response22;
//得到文本框的数据
varname=document.getElementById("username").value;
//发送http请求,把要检测的用户名传递进去
httpRequest.send("username="+name);
}
functionresponse22(){
//判断请求状态码是否是4【数据接收完成】
if(httpRequest.readyState==4){
//再判断状态码是否为200【200是成功的】
if(httpRequest.status==200){
//得到服务端返回的文本数据
vartext=httpRequest.responseText;
//把服务端返回的数据写在div上
vardiv=document.getElementById("result");
div.innerText=text;
}
}
}
效果实现了局部更新,不需要刷新整一个页面XMLHttpRequest解决中文乱码在传统的Web中我们已经解决过中文乱码问题了。
服务器传送给浏览器数据发生乱码:response设置编码的时候和浏览器页面的编码一致便可以解决
浏览器传送给服务器数据发生乱码:如果是post方式,request设置编码便可以解决。如果是get方式,Tomcat下,使用ISO8859-1编码得到原本的二进制数组,再使用UTF-8编码便可以解决
接下来,要介绍的是:我们可以屏蔽任何浏览器和任何服务器的编码格式,浏览器发送给服务器的数据不造成乱码问题!具体我们是这样做的:
发送数据给服务器的时候,JavaScript使用两次EncodeURI()
服务器得到数据,使用URLEncode.decode(数据,"utf-8")进行解码
为啥我能说这种方式屏蔽任何浏览器和服务器的编码格式,都不会乱码呢??XMLHttpRequest解决缓存问题在传统的Web中我们也解决过缓存的问题,通过设置response的头信息,返回给浏览器就可以实现不缓存页面了。但是呢,现在我们使用XMLHttpRequest,拿到的不是全新的页面,仅仅是服务器端发送过来的数据!!那我们要怎么解决缓存的问题呢??产生缓存的原因就是:我们请求了同一个地址,做了相同的操作。服务端认为我的操作并没有什么变化,就直接把缓存的信息给我了。这样的话,我就不能更换验证码图片了(等等应用)。我们可以这样做:
在每次请求url中加入一个时间戳参数【每次url就不一样了】
加入时间戳参数到url时,也分两种情况
url本身就带有参数了,也就是说有"?"号了,那么添加时间戳的时候就需要用"&"号
url没有参数,直接使用"?"号来添加时间戳
if(url.indexOf("?")>=){
url=url+"&t="+(newDate()).valueOf();
}else{
url=url+"?t="+(newDate()).valueOf();
}
XMLHttpRequest跨域访问使用XMLHttpRequest去跨域访问是会出现错误的。我们要怎么解决呢??这时候就要用代理思想了
XMLHttpRequest先把请求提交给同域的Servlet处理
同域Servlet再将XMLHttpRequest的请求提交给跨域的服务器
同域Servlet得到跨域服务器的返回值,再返回给XMLHttpRequest
这个时候,XMLHttpRequest跨域访问就分两种(GET和POST)情况了,因为这两种提交数据的方式是不一样的!浏览器代码
我们需要在调用open方法之前判断一下要连接的地址是不是以http开头的,如果是则认为要访问的是跨域的资源
首先将当前url中的”?”变成”&”,这是因为将要连接的地址改为”Proxy?url=” + url以后,如果原来url地址中有参数的话,新的url地址中就会有两个“?”这会导致服务器端解析参数错误,”url=”之后的内容表示本来要访问的跨域资源的地址。
GET方式GET方式是直接把参数的信息都放在url地址上,所以处理起来会相对简单。步骤:
使用StringBuilder装载着getParameter("url")【获取得到地址,呆会要做拼接,所以用StringBuilder】
得到其他参数的时候,做URLEncode.encode(),因为我们进入Servlet的时候已经被decode了一次【我们要尽可能保留原始请求】(参照解决中文乱码)
遍历所有的请求参数,只要名字不是"url",就添加到StringBuilder中【第一个参数为"?",其他的参数为"&"】(http://localhost:8080/url?aa=bb&cc=dd)
创建URL对象,把拼接成的StringBuilder传递进去
使用BufferReader读取远程服务器返回的数据,要指定输入流编码格式,否则会乱码
BufferedReaderreader=newBufferedReader(newInputStreamReader(URL对象.openSteam(),"UTF-8"));
最后,把远程服务器读取到的数据再返回给XMLHttpRequest
POST方式POST方式把参数的信息都封装到HTTP请求中,在URL进行连接的时候,需要把数据写给远程服务器步骤:
得到url参数,创建StringBuilder
得到其他参数的时候,做URLEncode.encode(),因为我们进入Servlet的时候已经被decode了一次【我们要尽可能保留原始请求】(参照解决中文乱码)
遍历所有的请求参数,只要名字不是"url",就添加到StringBuilder中【第一个参数直接给出,其他的参数为"&"】(aa=bb&cc=dd&ee=ff)
创建URL对象,创建URL连接器,允许写数据到远程服务器上
URLurl=newURL(url);
URLConnectionconnection=url.openConnection;
connection.setDoOutPut(true);
得到写数据流
OutputSteamWriterwriter=newOutputSteamWriter(conncetion.getOutputSteam)
把StringBuilder的数据写到远程服务器上,并flush
使用BufferReader读取远程服务器返回的数据
BufferedReaderreader=newBufferedReader(newInputSteamReader(conncetion.inputSteamReader,"UTF-8"));
AJAX二级下拉联动案例【XML版】我们在购物的时候,常常需要我们来选择自己的收货地址,先选择省份,再选择城市...有没有发现:当我们选择完省份的时候,出现的城市全部都是根据省份来给我们选择的。这是怎么做到的呢???其实就是通过AJAX来完成的。使用AJAX技术让我们看起来网页非常“智能”,会根据省份来给出对应的城市信息。我们这里就不读取数据库了,直接在Servlet写死数据来进行模拟测试。分析我们知道AJAX与服务器之间的交互常用的传输载体格式有三种:
HTML
XML
JSON
由于省份与城市是有层级关系的,因此我们只能用XML或者JSON。我们这里首先就用XML来进行,后面会使用JSON,来看看他俩有什么不同的地方。。前台分析当用户选择了某个省份之后,就使用AJAX与服务器进行交互,那么在选择城市的时候就出现对应的城市信息。
监听下拉框值变化事件
只要下拉框值变化了,就与服务器进行交互
得到服务器返回的值,解析XML
使用DOM把数据写到城市下拉框列表中
后台分析
得到前台带过来的数据
判断该数据是什么,返回对应的的XML文件
写JSP页面
CreatedbyIntelliJIDEA.
User:ozc
Date:2017/5/17
Time:19:38
TochangethistemplateuseFileSettingsFileTemplates.
--%>
多级联动
请选择省份
广东
湖南
请选择城市
document.getElementById("provinceId").onchange=function(){
/**********定位到下拉框,获取下拉框的值***************/
// 获取选中的下拉框索引值
varindex=this.selectedIndex;
// 得到下拉框的值
varprovince=this.options[index].innerHTML;
//下拉框的值要是“请选择”,那么我们是不会访问服务器的
if("请选择省份"!=province){
/********由于每次都会自动添加,因此每次在调用的时候清除***********/
varcitySelect=document.getElementById("cityId");
//每次都将option变成长度只有1的
citySelect.options.length=1;
/*************ajax代码*********************/
//创建AJAX对象
varajax=createAJAX();
//准备发送请求
varmethod="post";
varurl="$/ProvinceServlet?time="+newDate().getTime();
ajax.open(method,url);
//由于是POST方式,因此要设置头
ajax.setRequestHeader("content-type","application/x-www-form-urlencoded");
ajax.send("province="+province);
/************ajax回调函数*********************/
ajax.onreadystatechange=function(){
if(ajax.readyState==4){
if(ajax.status==200){
//得到服务器端带过来的XML
varXMLDocument=ajax.responseXML;
/**********解析XML文档,使用DOM写到下拉框中****************/
varcities=XMLDocument.getElementsByTagName("city");
//得到每一个cities节点的值,动态生成下拉框,添加到下拉框中
for(vari=;i
varvalue=cities[i].firstChild.nodeValue;
//动态生成下拉框
varoptionElement=document.createElement("option");
optionElement.innerHTML=value;
//添加到下拉框中
citySelect.appendChild(optionElement);
}
}
}
};
}
};
Servlet
importjava.io.IOException;
importjava.io.PrintWriter;
/**
* Created by ozc on 2017/5/17.
*/
@javax.servlet.annotation.WebServlet(name="ProvinceServlet",urlPatterns="/ProvinceServlet")
publicclassProvinceServletextendsjavax.servlet.http.HttpServlet{
protectedvoiddoPost(javax.servlet.http.HttpServletRequestrequest,javax.servlet.http.HttpServletResponseresponse)throwsjavax.servlet.ServletException,IOException{
//设置中文编码
request.setCharacterEncoding("UTF-8");
Stringprovince=request.getParameter("province");
//这里是返回的是XML,因此指定XML数据!
response.setContentType("text/xml;charset=UTF-8");
PrintWriterprintWriter=response.getWriter();
/****************返回XML文件给前台**************/
printWriter.write("");
printWriter.write("");
if("广东".equals(province)){
printWriter.write("广州");
printWriter.write("深圳");
printWriter.write("中山");
}elseif("湖南".equals(province)){
printWriter.write("长沙");
printWriter.write("株洲");
printWriter.write("湘潭");
printWriter.write("岳阳");
}
printWriter.write("");
System.out.println("1111");
/*******事后操作*******/
printWriter.flush();
printWriter.close();
}
protectedvoiddoGet(javax.servlet.http.HttpServletRequestrequest,javax.servlet.http.HttpServletResponseresponse)throwsjavax.servlet.ServletException,IOException{
this.doPost(request,response);
}
}
效果:XML方式总结
监听下拉框的变化,如果变化了,那么就使用异步操作去访问服务器,得到对应的数据返回给异步对象
异步对象解析服务器带过来的数据,使用DOM编程把数据动态添加到页面上
在Servlet上记得要指定返回的是XML的数据!
在前台解析XML文档的时候,不能直接使用innerHtml来得到节点的值,只能通过firstChild.nodeValue的方式获取。
由于每次append到下拉框都会连续append,因此在响应事件的时候,把下拉框清零
把下拉框options的长度赋值为1,那么就是清零的操作了。
AJAX二级下拉联动案例【JSON版】前面我们已经使用过了XML作为数据载体在AJAX中与服务器进行交互。当时候我们的案例是二级联动,使用Servlet进行控制这次我们使用JSON作为数据载体在AJAX与服务器交互,使用三级联动,使用Action进行控制....
省份-城市-区域三级联动【Struts2 + JSON版】
分析与上次是一样的,只不过这次换了用JSON,使用Action控制罢了...监听下拉框的变动,使用异步对象与服务器进行交互。前台分析
监听下拉框的变动
得到服务器返回的JSON数据
使用eval()进行解析,得到具体的对象
使用DOM编程把数据填充到对应的下拉框上
后台分析
得到前台发送过来的数据
判断具体的数据是什么,给出对应的数据
使用Struts2提供的组件把数据封装成JSON
返回给浏览器
监听省份JSP页面
Created by IntelliJ IDEA.
User: ozc
Date: 2017/5/18
Time: 13:36
To change this template use File Settings File Templates.
--%>
使用JSON数据载体与服务器进行交互
请选择省份
广东
北京
请选择城市
请选择区域
document.getElementById("provinceId").onchange=function(){
// 得到选中的下拉框的值
varprovinceValue=this.options[this.selectedIndex].innerHTML;
/***************ajax代码*************************/
if("请选择省份"!=provinceValue){
//每次访问的时候,都要清空select的值
varcitySelect=document.getElementById("cityId");
citySelect.options.length=1;
varajax=createAJAX();
varmethod="post";
varurl="$/province_findCityByProvince?time="+newDate().getTime();
ajax.open(method,url);
ajax.setRequestHeader("content-type","application/x-www-form-urlencoded");
//顾及到发送的key、value值有很多,于是我们使用对象吧。
ajax.send("bean.name="+provinceValue);
/***************等待服务器的响应,得到服务器返回的数据************************/
ajax.onreadystatechange=function(){
if(ajax.readyState==4){
if(ajax.status==200){
varjsonJava=ajax.responseText;
//解析成是JS类型的JSON
varjson=eval("("+jsonJava+")");
//得到每个城市的值
for(vari=;i
varcity=json.city[i];
//动态创建option控件
varoption=document.createElement("option");
option.innerHTML=city;
citySelect.appendChild(option);
}
}
}
};
}
};
监听省份Action要想Struts2能够把Action的数据封装成JSON,就需要导入Struts2的开发包
struts2-json-plugin-2.3.4.1.jar
在Action中对应的成员属性需要给getter方法
importcom.opensymphony.xwork2.ActionSupport;
importjava.util.ArrayList;
importjava.util.List;
/**
* Created by ozc on 2017/5/18.
*/
publicclassProvinceActionextendsActionSupport{
//自动封装数据
privateBeanbean;
publicBeangetBean(){
returnbean;
}
publicvoidsetBean(Beanbean){
this.bean=bean;
}
//封装城市的集合
privateListcity=newArrayList();
publicListgetCity(){
returncity;
}
publicStringfindCityByProvince()throwsException{
if("广东".equals(bean.getName())){
city.add("广州");
city.add("珠海");
city.add("从化");
}elseif("北京".equals(bean.getName())){
city.add("一环");
city.add("二环");
city.add("三环");
city.add("四环");
}else{
System.out.println("没有你选择的地区");
}
return"ok";
}
}
返回给前端的时候,数据是这样子的:效果监听城市JSP
document.getElementById("cityId").onchange=function(){
//清空值
varareaSelect=document.getElementById("areaId");
areaSelect.options.length=1;
//得到选择选中的下拉框的值
varcityValue=this.options[this.selectedIndex].innerHTML;
if(cityValue!="请选择城市"){
varajax=createAJAX();
varmethod="post";
varurl="$/province_findAreaByCity?time="+newDate().getTime();
ajax.open(method,url);
ajax.setRequestHeader("content-type","application/x-www-form-urlencoded");
//顾及到发送的key、value值有很多,于是我们使用对象吧。
ajax.send("bean.name="+cityValue);
/***************等待服务器的响应,得到服务器返回的数据************************/
ajax.onreadystatechange=function(){
if(ajax.readyState==4){
if(ajax.status==200){
varjsonJava=ajax.responseText;
varjson=eval("("+jsonJava+")");
//得到每个地区的值
for(vari=;i
vararea=json.area[i];
//动态创建option控件
varoption=document.createElement("option");
option.innerHTML=area;
areaSelect.appendChild(option);
}
}
}
}
};
};
Action页面最终效果:总结这次使用的是JSON作为数据载体与服务器进行交互,和XML本质上是没有区别的。只不过JSON是更加轻量级文本数据,在JavaScript能够方便地获取返回的数据
在Struts2中把Action数据封装成JSON格式,返回给异步对象
需要导入jar包
在配置文件中配置继承json包
返回的类型是json
如果使用POST时,发送的key、vaulue太多的话,我们可以使用bean进行封装
当选中省份时,把城市和区域的下拉框清空,当选择城市时,把区域的下拉框清空
总结图
领取专属 10元无门槛券
私享最新 技术干货