【AJAX】
一 AJAX引入
1.1认识同步交互和异步交互
1.1.1什么是同步交互
首先用户向HTTP服务器提交一个处理请求。接着服务器端接收到请求后,按照预先编写好的程序中的业务逻辑进行处理,比如和数据库服务器进行数据信息交换。最后,服务器对请求进行响应,将结果返回给客户端,返回一个HTML在浏览器中显示,通常会有CSS样式丰富页面的显示效果。
优点
可以保留浏览器后退按钮的正常功能。在动态更新页面的情况下,用户可以回到前一个页面状态,浏览器能记下历史记录中的静态页面,用户通常都希望单击后退按钮时,就能够取消他们的前一次操作,同步交互可以实现这个需求.
缺点
- 同步交互的不足之处,会给用户一种不连贯的体验,当服务器处理请求时,用户只能等待状态,页面中的显示内容只能是空白。
- 因为已经跳转到新的页面,原本在页面上的信息无法保存,好多信息需要重新填写
1.1.2什么是异步交互
指发送一个请求,不需要等待返回,随时可以再发送下一个请求,即不需要等待。在部分情况下,我们的项目开发中都会优先选择不需要等待的异步交互方式。将用户请求放入消息队列,并反馈给用户,系统迁移程序已经启动,你可以关闭浏览器了。然后程序再慢慢地去写入数据库去。这就是异步。异步不用等所有操作等做完,就相应用户请求。即先相应用户请求,然后慢慢去写数据库,用户体验较好
优点
- 前端用户操作和后台服务器运算可以同时进行,可以充分利用用户操作的间隔时间完成运算
- 页面没有跳转,响应回来的数据直接就在原页面上,页面原有信息得以保留
缺点
可能破坏浏览器后退按钮的正常行为。在动态更新页面的情况下,用户无法回到前一个页面状态,这是因为浏览器仅能记录的始终是当前一个的静态页面。用户通常都希望单击后退按钮,就能够取消他们的前一次操作,但是在AJAX这样异步的程序,却无法这样做。
1.2AJAX介绍
AJAX 即
“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式、快速动态网页应用的网页开发技术,无需重新加载整个网页的情况下,能够更新部分网页的技术。通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
AJAX关键技术
使用CSS构建用户界面样式,负责页面排版和美工
使用DOM进行动态显示和交互,对页面进行局部修改
使用XMLHttpRequest异步获取数据
使用JavaScript将所有的元素绑定在一起
AJAX的最大的特点: 异步访问,局部刷新
本节作业
- 什么是同步交互和异步交互?二者优缺点是什么?
- 什么是AJAX?AJAX由哪些技术组成?有什么特点?
二 JS实现AJAX案例
2.1 AJAX之验证用户名是否被占用
JS表单验证只能校验格式是否正确,但是无法验证用户名是否已经存在,这个就需要后台程序接受到数据后通过查询才能够完成的,那么这里就非常适用于使用异步方式校验,保证用于数据提交后,业务完成的成功率.提升用于体验感
页面代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户注册验证</title>
<script>
var xhr
function checkUser(){
/*1 获取用户名输入框中的数据*/
var uname =document.getElementById("uname").value;
/*2验证用户名是否为空*/
if(null == uname || uname == ''){
document.getElementById("uname_info").innerText="用户名不能为空";
return;
}
/*3验证数据不为空 验证通过 将提示清空*/
document.getElementById("uname_info").innerText="";
/*2使用AJAX向后台提交数据*/
/*原生js AJAX数据处理的四个步骤*/
/*1 获取XMLHTTPRequest对象*/
xhr=new XMLHttpRequest();
/*2打开链接 method 数据提交的方式 url 数据提交的地址 sync 是否异步*/
/*xhr.open("GET","/testAJAX1/LoginServlet?uname="+uname,true)*/
xhr.open("GET","loginServlet?uname="+uname,true);
/*3设置回调函数 数据响应回来后会触发的方法*/
xhr.onreadystatechange=showRnturnInfo;
/*4提交 数据 post方式 有意义*/
xhr.send(null)
}
function showRnturnInfo(){
var info =xhr.responseText;
document.getElementById("uname_info").innerText=info;
}
</script>
</head>
<body>
<%--页面 信息提交处理--%>
<p>
账号:<input type="text" name="uname" id="uname" onblur="checkUser()"/>
<span id="uname_info"></span>
</p>
<p>
密码:<input type="text" name="pwd" id="pwd"/>
</p>
<p>
<input type="submit" value="提交"/>
</p>
</body>
</html>
后台Servlet代码
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
@Override
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String uname = req.getParameter("uname");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/Html;charset=UTF-8");
PrintWriter out = resp.getWriter();
if("sxt".equals(uname)){
out.print("用户名被占用");
}else{
out.print("用户名可用");
}
}
}
总结
AJAX异步提交请求的步骤为
- 获取XMLHTTPRequest对象xhr=new XMLHttpRequest();
- 打开链接 xhr.open("GET","loginServlet?uname="+uname,true);
- 设置回调函数xhr.onreadystatechange=showRnturnInfo;
- 提交数据 xhr.send(data)
目前存在的问题:
原生js提交AJAX异步请求代码比较繁琐,处理复杂数据比较麻烦,后续可以使用jQuery解决
2.2 原生JS实现异步的常见问题及解决方案
2.2.1代码兼容性问题
早期的浏览器不支持直接 new XMLHTTPReuquest 可以通过 new ActiveXObject("Microsoft.XMLHTTP");
/*处理早期浏览器 内核写法 目前比较少见 除非对 浏览器有特殊 要求*/
if(window.ActiveXObject){
xhr=new ActiveXObject("Microsoft.XMLHTTP");
}else{
xhr=new XMLHttpRequest();
}
2.2.2post方式如何提交数据
open方法中选择POST, xhr.send时提交数据
xhr.open("POST","loginServlet",true)
/*POST 方式 提交数据 需要设置请求头为普通文本数据提交*/
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
/*设置回调函数 数据响应回来后会触发的方法*/
xhr.onreadystatechange=showRnturnInfo;
/*post方式提交数据 */
xhr.send("uname="+uname);
2.2.3回调函数多次被调用问题
XMLHTTPequest的几种状态
readyState代表请求的状态或者形情
0:请求没有发出(在调用open()之前)
1:请求已经建立但是还没有发出(调用send()之前)
2:请求已经发出正在处理之中(这里通常可以从响应的到内容头部)
3:请求已经处理,响应中有数据可用,但是服务器还没有完成响应
4:响应已经完成,可以访问服务器响应并使用它
在AJAX中有以上五种状态,但是通常只使用状态4
status代表响应状态码:
200
404
XMLHTTPequest返回的数据格式
responseText 普通文本格式
responseXML xml格式
在回调函数中我们可以通过readyState和status来判断请求的状态,然后做出不同的处理,但是绝大部分情况我们只做响应完成之后的代码即可,返回的数据目前我们暂时使用responseText普通文本格式,后面可以使用json
<script>
var xhr
function checkUser(){
var uname =document.getElementById("uname").value;
if(null == uname || uname == ''){
document.getElementById("uname_info").innerText="用户名不能为空";
return;
}
document.getElementById("uname_info").innerText="";
xhr=new XMLHttpRequest();
/*alert("在打开链接之前xhr的状态"+xhr.readyState)*/
xhr.open("POST","loginServlet",true)
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
xhr.onreadystatechange=showRnturnInfo;
/*alert("在数据发送之前xhr的状态"+xhr.readyState)*/
xhr.send("uname="+uname);
}
function showRnturnInfo(){
/*输出证明回调函数会被调用多次但是我们仅仅需要在响应完成之后才需要设置据
这样的设计是为了可以让回调函数在不同的请求状态下都 可以有响应的处理代码
*/
/* alert("回调函数中xhr的状态"+xhr.readyState)*/
/*alert(xhr.status);*/
if(xhr.readyState==4&&xhr.status==200){
var info =xhr.responseText;
document.getElementById("uname_info").innerText=info;
}
}
</script>
2.3 案例开发,原生js AJAX实现二级联动
目标效果
前端代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>二级联动实现</title>
<script>
var xhr;
function change(val){
/*发送 AJAX 请求*/
xhr =new XMLHttpRequest();
/*建立链接*/
xhr.open("GET","changeServlet?country="+val,true)
/*设置回调方法*/
xhr.onreadystatechange=showFood
/*发送数据*/
xhr.send(null)
}
function showFood(){
if(xhr.readyState==4&&xhr.status==200) {
var foodsList =xhr.responseText;
/*响应回来的其实是像集合的一个字符串*/
var foodsWords =foodsList.substring(1,foodsList.length-1)
var foods = foodsWords.split(", ");
/*将数据设置进food标签*/
var foodTag =document.getElementById("food");
/*清空原有数据*/
foodTag.innerHTML="<option selected>-请选择食品-</option>";
/*设置新的数据*/
for(var i in foods){
foodTag.innerHTML+="<option>"+foods[i]+"</option>"
}
}
}
</script>
</head>
<body>
<select id="country" name="country" onchange="change(this.value)">
<option selected value="0">-请选择口味-</option>
<option value="1">日韩</option>
<option value="2">欧美</option>
<option value="3">国产</option>
</select>
<select id="food" name="food">
<option selected>-请选择食品-</option>
</select>
</body>
</html>
后台代码:
@WebServlet("/changeServlet")
public class ChangeServlet extends HttpServlet {
@Override
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String country = req.getParameter("country");
System.out.println(country);
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/Html;charset=UTF-8");
PrintWriter out = resp.getWriter();
List<String> foods =new LinkedList<String>();
if(country.equals("1")){
foods.add("寿司");
foods.add("泡菜");
foods.add("金枪鱼");
}else if(country.equals("2")){
foods.add("汉堡");
foods.add("炸鸡");
foods.add("奥尔良烤翅");
}else if(country.equals("3")){
foods.add("烤串");
foods.add("火锅");
foods.add("东北乱炖");
}else{
foods.add("该地区无食物");
}
/*响应数据*/
out.print(foods);
}
}
总结
目前servlet向浏览器响应的数据其实是toString()方法生成的字符串,浏览器接收到字符串之后,需要严重依赖string的API去完成字符串解析,代码繁琐,而且面对复杂数据时,解析非常麻烦.为了解决这一问题,我们可以使用JSON格式处理响应数据.
本节作业
- 原生JS实现AJAX有哪些步骤?
- XMLHttpRequest对象有中有哪些状态?对应的状态描述值分别是什么?
- 实现验证用户名是否被占用案例
三 AJAX响应数据格式处理
3.1 响应普通文本数据
如果服务器给我们响应的数据非常简答,那么使用字符串就好了,不需要我们做复杂的处理,后台编码也简单.
页面代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>AJAX数据响应格式</title>
<script>
var xhr;
function getData(){
xhr =new XMLHttpRequest();
xhr.open("GET","testDataServlet",true)
xhr.onreadystatechange=showData
xhr.send(null)
}
function showData(){
if(xhr.readyState==4&&xhr.status==200) {
var text =xhr.responseText;
console.info(text)
}
}
</script>
</head>
<body>
<button type="button" onclick="getData()" >触发</button>
</body>
</html>
后台代码:
@WebServlet("/testDataServlet")
public class TestDataServlet extends HttpServlet {
@Override
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.getWriter().print("普通文本数据");
}
}
总结:
如果响应的数据是一个对象或者对象集合,数据处理起来会非常麻烦,可以使用JSON格式处理
3.2 JSON的介绍
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
它有如下优点
- 轻量级,在这里用它不是为了厉害的功能代码,而是为了实现数据转换
- Json 格式既能考虑到前端对象的特点 同时也能兼顾后台对象信息的特点
- Json 格式可以被前端直接识别并解析成对象
- jQuery形式实现AJAX默认前后端传递数据的格式就是JSON
java中创建对象的语法(重量级语法)
class Person{
private int id;
private String name;
private String gender;
public void eat(){
}
}
JSON格式在前端创建对象的语法(轻量级语法)
{
属性名:属性值,
属性名:属性值,
方法名:function(){
}
}
3.2.1在JS中定义单个对象
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script>
var person={
name:'李雷',
gender:'男',
study:function(){
console.info(this.name+"正在学习寻找韩梅梅的方法")
}
}
console.info(person.name)
person.study();
</script>
</head>
<body>
</body>
</html>
3.2.2在JS定义多个对象集合
< script >
var persons = [
{
name: '李雷',
gender: '男',
study: function() {
console.info(this.name + "正在学习寻找韩梅梅的方法")
}
},
{
name: '韩梅梅',
gender: '女',
study: function() {
console.info(this.name + "正在学习寻找李雷的方法")
}
},
{
name: '小明',
gender: '男',
study: function() {
console.info(this.name + "正在找不用滚出去的方法")
}
}]
for (var i in persons) {
console.info(persons[i].name) persons[i].study()
}
$.each(persons,
function(i, e) {
console.info(e.name) e.study()
})
< /script>
JSON 与 JS 对象的关系
很多人搞不清楚 JSON 和 JS 对象的关系,甚至连谁是谁都不清楚。其实,可以这么理解:JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
var obj = {a: 'Hello', b: 'World'}; //这是一个JS对象,注意键名也是可以使用引号包裹的
var json = '{"a": "Hello", "b": "World"}'; //这是一个 JSON 字符串,本质是一个字符串
JSON 和 JS 对象互转
要实现从JSON字符串转换为JS对象,使用 JSON.parse() 方法:
var obj = JSON.parse('{"a": "Hello", "b": "World"}'); //结果是 {a: 'Hello', b: 'World'}
要实现从JS对象转换为JSON字符串,使用 JSON.stringify() 方法:
var json = JSON.stringify({a: 'Hello', b: 'World'}); //结果是 '{"a": "Hello", "b": "World"}'
3.3 使用JSON实现数据交互
3.3.1手动实现数据转换
页面代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>AJAX数据响应格式</title>
<script>
var xhr;
function getData(){
xhr =new XMLHttpRequest();
xhr.open("GET","testDataServlet",true)
xhr.onreadystatechange=showData
xhr.send(null)
}
function showData(){
if(xhr.readyState==4&&xhr.status==200) {
var userText =xhr.responseText;
/*运行JSON字符串 生成一个JS对象*/
eval('var user='+userText)
console.info(user.birthday)
}
}
</script>
</head>
<body>
<button type="button" onclick="getData()" >触发</button>
</body>
</html>
后台代码:
@WebServlet("/testDataServlet")
public class TestDataServlet extends HttpServlet {
@Override
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
resp.setCharacterEncoding("UTF-8");
User user =new User(1,"aaa",new Date());
/*手动拼接JSON字符串*/
String userJson="{id:"+user.getId()+",name:'"+user.getName()+"',birthday:'"+user.getBithday()+"'}";
resp.getWriter().print(userJson);
}
}
问题:
JSON格式字符串,拼接比较麻烦,可以修改toString方法但是就破坏了toString原有的格式,而且一旦字段如果太多修改工作量大,后面可以使用JSON工具类转换
3.3.2使用GSON工具类
gson工具类中已经给我们封装好了json格式和java对象之间转换的API,我们直接使用即可,再也不用手动去转换项目中
添加gson-2.2.4.jar
响应单个对象
前端代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>AJAX数据响应格式</title>
<script>
var xhr;
function getData(){
xhr =new XMLHttpRequest();
xhr.open("GET","testDataServlet",true)
xhr.onreadystatechange=showData
xhr.send(null)
}
function showData(){
if(xhr.readyState==4&&xhr.status==200) {
var userText =xhr.responseText;
/*使用JSON对象自动将字符串转换为接收对象
使用此种方式 后台必须使用GSON 生成对象JSON字符串
否则 手动拼接时 键必须用单引号包裹起来
*/
var user=JSON.parse(userText)
console.info(user.bithday)
}
}
</script>
</head>
<body>
<button type="button" onclick="getData()" >触发</button>
</body>
</html>
后台代码:
@WebServlet("/testDataServlet")
public class TestDataServlet extends HttpServlet {
@Override
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
resp.setCharacterEncoding("UTF-8");
User user =new User(1,"aaa",new Date());
Gson gson =new Gson();
String userJson=gson.toJson(user);
resp.getWriter().print(userJson);
}
}
使用JSON响应对象集合
页面代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>AJAX数据响应格式</title>
<script>
var xhr;
function getData(){
xhr =new XMLHttpRequest();
xhr.open("GET","testDataServlet",true)
xhr.onreadystatechange=showData
xhr.send(null)
}
function showData(){
if(xhr.readyState==4&&xhr.status==200) {
var userText =xhr.responseText;
/*使用JSON对象自动将字符串转换为接收对象*/
var userList=JSON.parse(userText)
for(var i in userList){
console.info(userList[i].name)
}
}
}
</script>
</head>
<body>
<button type="button" onclick="getData()" >触发</button>
</body>
</html>
后台代码:
@WebServlet("/testDataServlet")
public class TestDataServlet extends HttpServlet {
@Override
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
resp.setCharacterEncoding("UTF-8");
User user1 =new User(1,"aaa1",new Date());
User user2 =new User(2,"aaa2",new Date());
User user3 =new User(3,"aaa3",new Date());
User user4 =new User(4,"aaa4",new Date());
List<User> userList =new LinkedList<User>();
Collections.addAll(userList,user1,user2,user3,user4);
Gson gson =new Gson();
String userJson=gson.toJson(userList);
resp.getWriter().print(userJson);
}
}
3.4 以XML格式响应数据(了解)
页面代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>AJAX数据响应格式</title>
<script>
var xhr;
function getData(){
xhr =new XMLHttpRequest();
xhr.open("GET","testDataServlet",true)
xhr.onreadystatechange=showData
xhr.send(null)
}
function showData(){
if(xhr.readyState==4&&xhr.status==200) {
var doc =xhr.responseXML;
var name =doc.getElementsByTagName("name")[0].innerHTML;
console.info(name)
}
}
</script>
</head>
<body>
<button type="button" onclick="getData()" >触发</button>
</body>
</html>
后台代码:
@WebServlet("/testDataServlet")
public class TestDataServlet extends HttpServlet {
@Override
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/xml;charset=UTF-8");
resp.setCharacterEncoding("UTF-8");
User user =new User(1,"aaa1",new Date());
/*拼接xml格式字符串*/
resp.getWriter().print("<student><id>"+user.getId()+"</id><name>"+user.getName()+"</name><bithday>"+user.getBithday()+"</bithday></student>");
}
}
本节作业
- 什么是JSON?为什么要使用它?
- 实现JSON格式传递多个对象案例