转自:https://www.cnblogs.com/dongfangshenhua/p/6858833.html
1、ajax介绍
1.1、什么是ajax
全称:Asynchronous JavaScript And XML(异步 JavaScript 及 XML)
Ajax的作用:实现异步请求的技术。
什么是同步请求?
场景:页面上有一个a标签,用户点击a标签,浏览器发出一个请求,然后服务器给出一个响应。
(请求,其实是用户的操作,触发的)
什么是异步(不同步)请求?
场景:在用户注册的时候,用户首先输入用户名,接下来用户继续填写其他注册信息,与此同时,浏览器自动发送了一个请求,将用户输入的用户名发送给服务器,去校验是否可用.
(请求,是浏览器自己发送的,与用户没有关系)
同步与异步区别的理解:
1.同步请求:之前我们写的注册案例,依次写用户名,密码,等等所有信息之后,手动按提交按钮,才会把浏览器上的数据传到服务器进行校验用户名是否重复,然后在浏览器上提示用户名是否重复的信息,这种方式一速度较慢,需要将全部信息写完之后刷新整个页面提交到服务器,如果没有通过验证还得重新填写信息再提交,比较浪费流量,二则是如果没有通过验证所有的信息都没有了还得重新填写,太麻烦
2.异步请求:使用ajax的话,将用户名文本框绑定一个鼠标离焦事件,事件里用ajax提交用户名到服务器校验,这个验证是我们鼠标离开用户名文本框浏览器自动向服务器发出请求校验的,我们在填写别的信息时,服务器会将校验信息发送给浏览器提示是否重复信息,这样既省流量,又可以只修改用户名即可,最后验证通过才可以提交全部信息;
为什么需要异步请求,或者说那些功能必须使用异步请求技术来实现?
在不刷新页面(使用a标签发送请求和使用form表单发送请求,这两种请求都会,刷新页面)的情况下,发送请求,接收响应,然后修改部分的页面,这样的需求需要异步请求实现。
总结:在不使用a标签和form表单发送请求的情况下,使用异步请求。
在这个需求中,发送请求应该谁来做?
浏览器。
让浏览器来帮助发送这个请求,那么程序员如何与浏览器沟通,让它帮助我们发送请求?
Javascript技术。
企业为什么特别喜欢使用ajax?
钱。企业的网络通信费用,按流量计费,那么使用ajax它的数据量小,所以省钱。
ajax它的数据量小——因为他不重新加载整个页面(加载部分)
Ajax因为数据量小,响应速度快,用户体验好。
1.2、ajax运行机制
在页面不刷新的情况下,向服务器发送请求,达到页面和后台的异步交互。
现在主流(IE、谷歌、火狐,其他的国产浏览器一般都是使用谷歌浏览器内核)的浏览器都有ajax引擎实现——现在ajax技术,都被主流浏览器实现,我们自己不用去写Ajax引擎,这个引擎已经存在在浏览器中。我们可以理解为浏览器都内置有ajax的核心对象,我们不需要自己创建核心对象,只要获取对象使用即可;
相当于大家已经有了法拉利,不用自己再造一个,只需学会使用就可以。
1.3、ajax快速入门案例
1)百度(官网)
2)下载jar和API文档
3)测试
4)笔记
注意:ajax没有jar包,所有不需要在项目中导入jar包;
1.3.1、获取XMLHttpRequest对象(ajax核心对象,引擎对象)
演示一: jsp代码: <script type="text/javascript"> //演示1:获取ajax的核心对象 //此为固定代码,因为浏览器不同则获取对象的方式处理也是不同的; function getXHR(){ var xmlhttp; if(window.XMLHttpRequest){ //如果使用的浏览器是 IE7+, Firefox, Chrome, Opera, Safari xmlhttp = new XMLHttpRequest(); }else{ //如果使用的浏览器是 IE6, IE5 xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } return xmlhttp; } //演示效果 //alert(getXHR()); </script>
效果:
1.3.2、向服务器发送请求使用open方法和send方法
演示二: jsp代码: //演示2,使用 ajax 向服务器发送请求 function test1(){ //先获取 ajax 核心对象(这个方法我们上面写过了,调用即可) var xhr = getXHR(); //使用open(method,url,async)方法发送请求 //参数一,method:请求的类型;GET 或 POST //参数二,url:文件在服务器上的位置 //参数三:async:true(异步)或 false(同步) xhr.open("get","${root}/ajax",true); //使用send()方法发送请求 //注意;此处是get提交,所以使用send方法没有参数 xhr.send(); } //test1();
效果:
注意:我们演示时还没有创建发送到服务器端的servlet,所有找不到资源;
1.3.2、接收服务器响应
演示三: jsp代码: //演示3,使用ajax,从服务器接收响应 function test2(){ //先获取ajax核心对象 var xhr = getXHR(); //参数一,method:请求的类型;GET 或 POST //参数二,url:文件在服务器上的位置 //参数三:async:true(异步)或 false(同步) //注意:此处的get提交,在url中添加了参数,发送到服务器 xhr.open("get","${root}/ajax?username=haha",true); //将请求发送到服务器。 xhr.send(); //接收响应,获取响应的内容 //接收服务器端的响应使用的是核心对象的 responseText属性 var data = xhr.responseText; //打印从服务器端发来的响应,"测试ajax响应成功!" alert(data); /** 浏览器:在上海 服务器:在北京 发送请求,请求到服务器,必然有网路延迟。 发送响应,响应到浏览器,必然有网路延迟。 必须等待服务器响应。所以还需要设置ajax等待服务器。 事件:用来启动js函数,调用js中方法,动态操作(增删改查Element)页面。 基于响应的任务? 注册:写用户名, 可用:表单可以提交 不可用:表单不能提交 */ } //演示效果 //test2();
AjaxServlet:这就是ajax发送请求到的服务器文件
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class AjaxServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { //获取 ajax 发送的参数 String parameter = request.getParameter("username"); //System.out.println(parameter); //准备一个响应,给浏览器(ajax核心对象) response.setContentType("text/html;charset=utf-8"); //注意:内容不会直接显示到浏览器页面上,从ajax发送的请求到服务器,从服务器返回的响应也会传到ajax中,由ajax做出处理 response.getWriter().write("测试ajax响应成功!"); } public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doGet(request, response); } }
效果:
浏览器效果应该是打印 "测试ajax响应成功!",但是什么都没有打印,所以出错了
控制台接收到了参数,说明服务器也响应了,出错的原因则一定是ajax没有接收到服务器的响应
所以还需要设置ajax等待服务器。如何设置呢?
1.3.3、设置onreadystatechange事件执行函数(等待服务器响应)
演示四: jsp代码: //演示4,设置等待服务器响应 function test3(){ //先获取ajax核心对象 var xhr = getXHR(); //第一,method:请求的类型;GET 或 POST //第二,url:文件在服务器上的位置 //第三:async:true(异步)或 false(同步) xhr.open("get","${root}/ajax",true); //将请求发送到服务器。 xhr.send(); //在接收响应前,设置等待服务器响应 xhr.onreadystatechange = function(){ if(xhr.readyState == 4 && xhr.status == 200){ //保证请求已经完成,且响应已经就绪 //接受响应 var data = xhr.responseText ; alert(data); } }; } //test3();
AjaxServlet:这就是ajax发送请求到的服务器文件
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class AjaxServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { //准备一个响应,给浏览器(ajax核心对象) response.setContentType("text/html;charset=utf-8"); //注意:内容不会直接显示到浏览器页面上,从ajax发送的请求到服务器,从服务器返回的响应也会传到ajax中,由ajax做出处理 response.getWriter().write("测试ajax响应成功!"); } public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doGet(request, response); } }
效果:成功
1.3.4.Ajax总结
Aja代码步骤:
1.获取核心对象 2.发送请求,使用open和send方法 3.设置等待服务器响应,给onreadystatechange属性设置函数,并且,在函数中做判断,保证readyState== 4 && status == 200,才是请求已经完成,响应已经就绪 4.获取响应的数据,根据需求,做Dom操作
最终版ajax代码:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <c:set var="root" value="${pageContext.request.contextPath}"/> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <script type="text/javascript"> //获取ajax的核心对象的方法 function getXHR(){ var xmlhttp; if(window.XMLHttpRequest){ //如果使用的浏览器是 IE7+, Firefox, Chrome, Opera, Safari xmlhttp = new XMLHttpRequest(); }else{ //如果使用的浏览器是 IE6, IE5 xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } return xmlhttp; } function test(){ //1.先获取ajax核心对象 var xhr = getXHR(); //第一,method:请求的类型;GET 或 POST //第二,url:文件在服务器上的位置 //第三:async:true(异步)或 false(同步) xhr.open("get","${root}/ajax",true); //2.将请求发送到服务器。 xhr.send(); //3.在接收响应前,设置等待服务器响应 xhr.onreadystatechange = function(){ if(xhr.readyState == 4 && xhr.status == 200){ //保证请求已经完成,且响应已经就绪 //4.接受响应 var data = xhr.responseText ; alert(data); } }; } test(); </script> </head> <body> </body> </html>
注意事项:
内容不会直接显示到浏览器页面上,从ajax发送的请求到服务器,从服务器返回的响应也会传到ajax中,由ajax做出处理
友情提示:
以后再工作中,一般不使用原生(今天学习的)的ajax代码,一般使用的是js框架(Jquery、ext js 、node js)发送ajax请求
问题:
Get发送请求与post发送请求的代码不同,我们还没有具体的分析,后文继续;
1.4、XMLHttpRequest API 详解
1.4.1、onreadystatechange属性
是什么:存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数
执行机制图解:
1.4.2、open方法
是什么:做发送请求之前准备工作的方法
一般使用post方式还是get方式?
官方建议:
我推荐:POST
POST,没有数据长度限制(注意:很多时候,提供功能给用户使用,用户输入的数据长度,有时是没法控制的)
POST,解决乱码比较简单
POST,方式更加安全
演示五: ajax代码: //演示5.使用post方式发送ajax请求 /** 测试js代码:firebug,会直接将出错的js代码位置,显示出来 如果firebug页也无法解决,使用alert(); */ function test4(){ var xhr = getXHR(); xhr.open("post","${root}/ajax",true); //模拟表单发送数据 xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); //js代码,如果代码中的某一行错了,它是不报错的, xhr.send("username=haha"); xhr.onreadystatechange = function(){ if(xhr.readyState == 4 && xhr.status == 200){ var data = xhr.responseText ; alert(data); } }; } test4();
AjacServlet:
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class AjaxServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { //获取post提交的参数 String parameter = request.getParameter("username"); System.out.println(parameter); //准备一个响应,给浏览器(ajax核心对象) response.setContentType("text/html;charset=utf-8"); //注意:内容不会直接显示到浏览器页面上,从ajax发送的请求到服务器,从服务器返回的响应也会传到ajax中,由ajax做出处理 response.getWriter().write("测试ajax响应成功!"); } public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doGet(request, response); } }
效果:post提交成功
1.4.3、setRequestHeader方法
注意:这个方法相当于,设置了表单的enctype属性的默认值,来模拟表单发送数据
1.4.4、send方法
是什么:发送请求的方法
注意:Post方式提交请求,请求参数写在send方法中。如果是get请求,参数,直接写在url中
1.4.5、总结:Get请求与post请求的对比
Post请求格式:
xhr.open("post","${root}/ajaxTest",true);
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); xhr.send("username=张三");
Get请求格式:
xhr.open("get","${root}/ajax?username=haha",true); xhr.send();
区别:
1.post提交的url中不可以带参数
2.Post提交需要设置:xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
3.Post提交的send方法参数就是post提交的参数,而get提交的send方法不可以有参数;
1.4.5、readyState属性
是什么:存有 XMLHttpRequest 的状态。从 0 到 4 发生变化
注意:我们只需要关注状态==4的时候,请求已经完成,而且响应已经就绪
1.4.6、status属性
是什么:存有响应状态码的属性
响应状态码:
404:请求找不到
500:服务器异常
302:重定向
200:ok
401:权限不足,做应用,对用户的界面(使用淘宝的时候买家看到的页面),对管理员界面(只有拥有管理员权限的用户,才能看到——卖家的页面),如果用户访问了管理员界面,那么就需要返回响应码为:401,表示当前用户权限不足。
管理员的页面:卖家(上传商品),客服(用户信息,用户的记录,电商,用户订单),运维(当前服务器的运行状态),老板(钱,当前系统的资金管理)
Shiro安全框架,权限
1.4.7、responseText属性
是什么:获取响应的数据,以字符串的形式
1.5、案例:验证用户名是否重复(重点:必须掌握)
需求:当用户输入完用户名的时候,浏览器发送用户输入的数据(用户名),给服务器,服务器校验用户名,并且给出反馈(用户名可以使用,用户名重复,用户名不能为空,服务器忙)。
思路:
1) 当用户输入完用户名的时候?oblur事件,启动js函数,发送ajax请求
2) 浏览器发送用户输入的数据(用户名),给服务器?Ajax
3) 服务器校验用户名?查询数据库
4) 并且给出反馈。Servelt给出响应,js处理这个响应,具体就是是否限制表单提交和提示用户错误信息
分析案例实现的步骤:
页面上提供功能:
1) 输入框,让用户输入用户名,表单提交数据
2) 提交按钮,提交数据
Ajax:
1) 获取用户输入的用户名
2) 发送请求
3) 等待响应
4) 根据响应做不同处理(可以提交表单和不可以提交)
Servlet:
1) 校验请求参数
2) 调用service方法查询
Service:
调用dao查询数据
Dao:
操作数据;
Select * from user where username = ?
画图分析:
功能实现:
页面修改:设置表单、输入框、提交按钮和js实现:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <c:set var="root" value="${pageContext.request.contextPath}"/> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <script type="text/javascript"> //获取ajax核心对象 function getXHR() { var xmlhttp; if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp = new XMLHttpRequest(); } else { // code for IE6, IE5 xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } return xmlhttp; } //_this 是绑定此事件的对象,注意因为参数是具体的标签对象,所以不可以使用关键字this function _check(_this){ //获取输入的用户名值 var username = _this.value; //发送到服务器校验是否有重名 //1.获取核心对象 var xhr = getHXR(); //2.发送请求 xhr.open("post","${root }/check",true); //模拟表单发送数据 xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); //注意:js代码,如果代码中的某一行错了,它是不报错的 xhr.send("username=" + username); xhr.onreadystatechange = function(){ if(xhr.readyState == 4 && xhr.status == 200){ var data = xhr.responseText; //注意:为了防止和js内置的全局变量,重名,所以加_ var _msg = document.getElementById("msg"); var _f = document.getElementById("_f"); if(data == 1){ //提示用户名可以注册 _msg.innerHTML = "用户名可以注册"; //onsubmit:表单提交事件 //只要onsubmit的值为true,表单才可以提交 _f.onsubmit = function (){ return true; }; } else if(data == -1){ _msg.innerHTML = "重复"; _f.onsubmit = function (){ return false; }; }else if(data == -3){ _msg.innerHTML = "用户名不能为空"; _f.onsubmit = function (){ return false; }; }else{ _msg.innerHTML = "服务器忙"; _f.onsubmit = function (){ return false; }; } } }; } </script> </head> <body> <form id="_f" action="${root }/register" method="post"> <!-- this:表示当前标签对象 --> 用户名:<input type="text" name="username" onblur="_check(this);"><span id="msg"></span> <br> <input type="submit" value="注册"> </form> </body> </html>
CheckNameServlet:
import java.io.IOException; import java.io.PrintWriter; import java.sql.SQLException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import cn.itcast.domain.User; import cn.itcast.utils.JDBCUtils; public class CheckNameServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { request.setCharacterEncoding("utf-8"); //获取请求参数 String username = request.getParameter("username"); //获取输出流 PrintWriter writer = response.getWriter(); //先校验用户名的格式 //用户名不能不写,也不能写空字符串 if(username == null || username.trim().equals("")){ //返回-3 writer.write("-3"); return; } //再校验用户名是否重复 //我们这里演示,就不使用service和dao,方法直接在servlet中实现,仅供演示使用 QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from user where name = ?"; try { User user = qr.query(sql, new BeanHandler<User>(User.class), username); if(user == null){ writer.write("1"); return; }else { writer.write("-1"); return; } } catch (SQLException e) { e.printStackTrace(); writer.write("-2"); return; } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
2、Ajax的缺陷
<!-- 使用JavaScript的标签解决,访问其他项目,获取响应数据 --> <!-- 解决ajax跨域问题 --> <script type="text/javascript"> function _response(data){ alert(data); } //_response('haha'); //_response('测试ajax成功day1802!'); </script> <%-- <script type="text/javascript" src="${root }/test.js"></script> --%> <script type="text/javascript" src="http://127.0.0.1:8080/day1802/ajax"></script>
//ajax缺陷演示 /** ajax,他可以访问其他项目的资源,但是,接受不到响应。这个是ajax设计的时候,为了考虑安全因素,专门设计的限制 实际的工作中,需要使用ajax发送请求,访问其他项目(例子:淘宝,买东西,选好了之后,支付,买东西的时候,你访问的是www.taobao.com ,支付,www.zhifubao.com) 那怎么解决呢? 使用JavaScript的标签解决。 */ /* function test5() { var xhr = getXHR(); xhr.open("post", "http://127.0.0.1:8080/day1802/ajax", true); xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); xhr.send("username=张三"); xhr.onreadystatechange = function() { //接受响应,readyState == 4 并且 status == 200 if (xhr.readyState == 4 && xhr.status == 200) { var data = xhr.responseText; alert(data); } }; } test5(); */