原生js的AJAX应用
传统请求的缺点
我们以前的学习过程,浏览器对服务器发出的请求,都是传统的全局刷新的请求.
如果我们仅仅只需要更新页面中的某一小块的内容,我们传统的全局刷新的形式,其他的部分也会随着需要更新的这一小块内容,也刷新一次.
我们现在想要的效果是,哪一块需要更新,就刷哪一块,其他的部分保持不动.这种请求,为局部刷新的请求.在浏览器上体现就是做操作以后,刷新按钮没有动
我们现在急需局部刷新的请求方式,来有效的提升用户体验.
AJAX技术应用带来的好处
ajax是一项JavaScript扩展的技术,ajax代码写在js中.
ajax技术最重要的功能是能够发出局部刷新的请求到后台servlet,servlet处理完请求后,为ajax响应一个返回值.ajax拿到返回值后,处理前端的业务逻辑.
原生js的AJAX实现步骤和同步异步操作
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
+ request.getContextPath() + "/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<base href="<%=basePath%>">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
function dj() {
//1.创建核心对象
/*
创建ajax的核心对象xmlhttp
以下所有的ajax功能的实现都是由该对象发起
*/
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");
}
//2.创建回调函数
/*
xmlhttp.onreadystatechange:
创建ajax的回调函数,ajax的回调函数指的是,先执行后台servlet,再执行该函数体.
*/
xmlhttp.onreadystatechange = function() {
/*
if表示回调函数的执行条件
xmlhttp.readyState:取得请求的状态码 码值为4 表示请求成功
xmlhttp.status:取得响应的状态码 码值为200 表示响应成功
回调函数的执行条件为,当请求成功并且响应成功的基础上,才执行该回调函数
*/
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
//xmlhttp.responseText接收后台servlet传递的返回值
//后台以响应流的形式传递的 out.print的内容就是ajax接收的返回值
var data = xmlhttp.responseText;
//在回调函数体中实现业务逻辑
document.getElementById("msg").innerHTML = data;
}
}
//3.设置请求信息
/*
xmlhttp.open
设置请求的基本信息
参数1:设置请求方式 GET/POST
参数2:设置请求路径
参数3:设置 同步请求还是异步请求
true:异步
上面的ajax代码和下面的alert弹框彼此之间没有互相影响
ajax的执行没有影响到alert的执行
alert的执行也没有影响到上面ajax的执行
全程为两根线程
一根执行ajax程序
一根执行alert弹框
异步为ajax与其他的程序自己执行自己的,不互相影响
false:同步
只有在执行完上面ajax代码之后,才能够执行下面的alert弹框
代码按照从上向下的顺序,依次执行.
全程一根线程
同步为ajax和其他程序,按照代码的顺序依次执行
在实际项目开发中,我们一般情况下,默认使用的都是异步操作,能够有效的提升用户体验,比如在显示页面的时候,有一块内容读取额较慢,但不影响其他块的内容显示
如果遇到特殊需求,我们也会使用到同步的技术,比如我们在验证表单时,有时需要只有填写的上一项内容通过,才能填写下一项内容
*/
xmlhttp.open("GET", "myServlet1.do?str1="+new Date().getTime(), false);
//post请求传递参数 这一行代表必须加在open方法和send方法的中间
//xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
//4.发送请求
//发送请求
xmlhttp.send("str1=ccc&str2=ddd");
//alert(123);
}
</script>
</head>
<body>
<button οnclick="dj()">点击</button>
<br />
<br />
<div style="width: 200px; height: 200px; background-color: pink" id="msg">
</div>
</body>
</html>
package com.jpg.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyServlet1 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("servlet1");
String str1 = request.getParameter("str1");
String str2 = request.getParameter("str2");
/*try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
/*
* 如果当前servlet接收的请求为传统的全局刷新的请求,那么响应流就是为浏览器做html代码的响应工作
* 如果当前servlet接收的请求为ajax发送的局部刷新的请求,那么响应流就是为ajax技术做返回值存在的 out.print中的内容,就是为ajax返回的值
*
*/
PrintWriter out = response.getWriter();
out.print(str1+";"+str2);
out.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
ajax以get请求方式传递参数
和传统的get请求传参数相同,在路径后面挂参数
xmlhttp.open(“GET”, "myServlet1.do?str1=aaa&str2=bbb, true);
ajax以post请求方式传递参数
使用ajax中避免浏览器缓存的方式
之所以走缓存,是因为浏览器认识了我们的请求路径,所以,想要避免缓存,让我们每一次的访问路径都不同,以挂参数的方式,但post不存在该问题,只针对get请求,因为post请求方式的路径的在地址栏不会显示
(1)随机数方式:
(2)时间戳方式:
JQuery支持的AJAX
$.ajax:最传统的基于jquery实现ajax的方式,这种方式最大的好处是使用方便,功能齐全.在实际项目开发中被普遍应用.(支持json)(用的其次)
$.get/$.post:这两种方式是基于以上$.ajax方式的简写形式,使用更加简单.在实际项目开发中使用的是最多的.但是由于应用比较简单,所以一些不常用的功能没有集成进来,所以,要有特殊需求的情况下,必须是在该方式的外部写额外的代码.(默认异步,想要修改,需要写额外的代码)(支持json)(用的最多)
$.getJSON:该方式除了能够有效的处理json数据之外,更重要的是能够读取json文件(用的不是很多)中的json内容.(用的较少)
$.ajax方式
$.ajax({
//type:"post", //请求方式 get/post 默认为get
url : "myServlet2.do", //请求路径 必要的
async: true, //表示同步或异步,true表示异步
dataType : "text", //从后台返回值的类型 text:普通文本(默认) json:json格式的文本
data : "str1=abc&str2=bcd", //请求参数
success : function(data) { //回调函数 data:从后台接收的返回值
$("#msg").html(data);
}
});
上述的dataType,如果后台设置相应的类型为:response.setContentType(“text/json;charset=utf-8”);则dataType可省略
$.get方式和$.post方式
默认异步,若需修改,在get或post外面修改
这种形式顺序不能乱,第一位是请求的路径
第二位是请求的参数
第三位是回调函数
第四位是从后台的返回值的类型
如果没有请求参数,直接删除即可,这样,回调函数排在第二位
$.get(
"myServlet1.do",
"username=zs&password=123", //以传统方式传参数
function(data) {
$("#msg").html(data);
},
"text"
);
JSON
语法
{“key1”:”value1”,”key2”:”value2”}
{key1:”value1”,key2:”value2”}
[{},{},{}] 集合
{“id”:”A0001”,”name”:”zs”,”age”:23}
key如果要加双引号,剩下的key都加,要不加,都不加
ajax以json格式传递参数
$.get(
"myServlet1.do",
{"username":username,"password":password}, //以json格式传参数
function(data) {
$("#msg").html(data);
},
"text"
);
ajax以json格式接收返回值(json的拼接)
拼接的步骤:
(1).写json模板
(2).将json模板粘贴到空串中
(3).将双引号转义
(4).为?赋值
1.接收单个值
2.接收多个值
//传递多个值
//{"str1":"aaa","str2":bbb}
String str = "{\"str1\":\"aaa\",\"str2\":\"bbb\"}";
3.接收单个对象
//接受单个对象
//{"id":"?", "name":"?", "age":?}
String str = "{\"id\":\""+s.getId()+"\", \"name\":\""
+s.getName()+"\", \"age\":"+s.getAge()+"}";
$.post(
"myServlet2.do",
function(data) {
alert(data.id);
},
"json"
)
4.接收多个对象
//接受多个对象
//{"id":"?", "name":"?", "age":?}
//{"s1":{"id":"?", "name":"?", "age":?}, "s2":{"id":"?", "name":"?", "age":?}}
String str = "{\"s1\":{\"id\":\""+s1.getId()+"\", \"name\":\""
+s1.getName()+"\", \"age\":"+s1.getAge()+"}, \"s2\":{\"id\":\""
+s2.getId()+"\", \"name\":\""+s2.getName()+"\", \"age\":"+s2.getAge()+"}}";
$.post(
"myServlet3.do",
function(data) {
alert(data.s2.id);
},
"json"
)
5.接收集合
public class MyServlet4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
Student s1 = new Student("A0001", "zs", 23);
Student s2 = new Student("A0002", "ls", 24);
Student s3 = new Student("A0003", "ww", 25);
Student s4 = new Student("A0004", "zl", 26);
Student s5 = new Student("A0005", "sq", 27);
List<Student> sList = new ArrayList<Student>();
sList.add(s1);
sList.add(s2);
sList.add(s3);
sList.add(s4);
sList.add(s5);
//接受集合
//{"id":"?", "name":"?", "age":?}
//{"sList":[{"id":"?", "name":"?", "age":?},{},{}]}
//我们需要使用循环的形式来拼接
StringBuffer buf = new StringBuffer();
buf.append("{\"sList\":[");
//使用普通for循环是因为我们需要使用到i,来拼接逗号
for(int i = 0; i < sList.size(); i++) {
Student s = sList.get(i);
//因为大量的+拼接,相当于String拼接,所以需要分开来append
//buf.append("{\"id\":\""+s.getId()+"\", \"name\":\""+s.getName()+"\", \"age\":"+s.getAge()+"}");
buf.append("{\"id\":\"");
buf.append(s.getId());
buf.append("\", \"name\":\"");
buf.append(s.getName());
buf.append("\", \"age\":");
buf.append(s.getAge());
buf.append("}");
if (i < sList.size() - 1) {
buf.append(",");
}
}
buf.append("]}");
out.print(buf.toString());
out.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<base href="<%=basePath%>">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="jquery/jquery-1.11.1-min.js"></script>
<script type="text/javascript">
$(function(){
$("#djBtn").click(function(){
//当每一次点击的时候,将原先展示的数据设置为空
$("#tbody").html("");
$.post(
"myServlet4.do",
function(data) {
/*
数据我们已经拿到了,我们以前的方式是拿到数据以后,将数据铺到table中,
我们以前使用的el和jstl,因为是全局刷新的方式,现在我们是以AJAX局部
刷新请求的方式拿到的数据,我们是使用的动态拼接table的方式,来将数据铺到table
*/
var i = 1;
//$(data.sList)拿到了json数组,将其转换成jQuery对象
$(data.sList).each(function(){
//每一个json对象使用this表示
$("#tbody").append("<tr><td>"+(i++)
+"</td><td>"+this.id+"</td><td>"+this.name
+"</td><td>"+this.age+"</td><td>删除||修改</td></tr>");
})
},
"json"
)
});
})
</script>
</head>
<body>
<button id="djBtn">点击</button><br>
<table border="1" align="center" width="70%" cellpadding="6px" cellspacing="0">
<thead>
<tr>
<td>序号</td>
<td>编号</td>
<td>姓名</td>
<td>年龄</td>
<td>操作</td>
</tr>
</thead>
<tbody id="tbody">
</tbody>
</table>
</body>
</html>
实战: 省市联动
需求:为点击的时候,两个下拉框中没有内容,当点击后,第一个下拉框显示省份,第二个框只要在选中省份后,才会显示对应的城市
省份表和城市表,一对多的关系,一个省份里面有多个城市,一个城市只能属于一个省份.
省份:一
城市:多
我们使用外键来描述表与表之间的关系
在谁的一方建立关系?(在哪张表中建立外键?)
永远是在多的一方建立关系(在多的一方建立外键)
省份表 tbl_province
id name
1 辽宁
2 吉林
3 黑龙江
城市表 tbl_city
id name pid
1 沈阳 1
2 大连 1
3 长春 2
如果外键换成pname可以吗?只记录下,该城市所属于的省份,这样不用多表联查,一张表搞定?也可以,但是存在缺点,第一:获取不到省份的其他信息,只能获取到省份名称,第二:数据得不到及时的更新,如果省份的名称发生了变化,那么城市表中的省份的字段的不到及时的更新,所以还是用pid作为外键合适
如果数据量过大,并且查询城市所属的省份很频繁,我们可以给城市表添加冗余字段pname,这样用一张表搞定,提高效率
关于建立外键有两种形式,一种是不直接建立外键,但是关系是外键关系,还有一种是真正的建立起外键(删除的麻烦),在实际项目开发中,一般采用第一种
$("#djBtn").click(function(){
//当每一次点击的时候,将原先展示的数据设置为空
$("#pid").html("<option value='-1'>-- 请选择 --</option>");
$.post(
"province/list.do",
function(data) {
$(data.pList).each(function(){
$("#pid").append("<option value="+this.id+">"+this.name+"</option>")
});
},
"json"
)
});
//判断下拉框的值是否变化,是change事件
$("#pid").change(function(){
$("#cid").html("<option value='-1'>-- 请选择 --</option>");
//选中option后会将option的value值赋值给select的value
var pid = $("#pid").val();
$.post(
"city/list.do",
"pid="+pid,
function(data) {
$(data.cList).each(function(){
$("#cid").append("<option value="+this.id+">"+this.name+"</option>")
});
},
"json"
)
});
转发形式向AJAX传返回值
如果是以request域+转发来向AJAX返回值,那么必须以json的形式来传数据,这样不会受到换行的影响,比如:
ajax请求传递:
$("#djBtn").click(function(){
$.post(
"myServlet1.do",
function(data){
//先弹出data,如果后台响应回的值等于aaa则弹出success
//在该程序中,是使用request+转发来给ajax返回值,因为是以文本的形式传数据,
//所以不会忽略换行的处理,最后返回的ajax的数据是两个换行+aaa,所以不会弹出success
//在转发的目标
alert(data);
if(data=="aaa"){
alert("success");
}
}
)
})
servlet处理:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("进入myServlet1");
String str1 = "aaa";
request.setAttribute("data",str1);
//如果写成以下json传输数据的格式,则会忽略换行,在该例子中会弹出success
//String str1 = "{\"str1\":\"aaa\"}";
//request.setAttribute("data",str1);
request.getRequestDispatcher("/data.jsp").forward(request, response);
}
转发的指定页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
${data}
$.getJSON的使用
我们以前都是发送请求到后台,从后台取数据,这种方式直接从json文件中取数据
这种方式中,从后台的返回值类型不用写,就是json
//为点击按钮绑定事件
$("#djBtn").click(function() {
$.getJSON(
"js/demo.json", //表示要读取的json文件的路径
function(data) {
alert(data.name);
}
)
})
ajax的跨域操作
什么是跨域操作
对于我们的ajax操作,都是从后台去取ajax的返回值.
我们都是从我们自己的项目的后台去取返回值
以前的形式
如果将路径加全
以上的访问路径,说明发出的ajax请求,是从我们自己的服务器的项目中的后台去取数据.
根据以上访问路径,其中的协议 ip 端口号,这3个条件,改变其中一种,就是跨域操作.
跨域操作,就是从别人家取数据
跨域操作案例
天气预报,腾讯qq的天气采用的是中国天气网的数据
实际项目开发中跨域的应用
以前
util包
domain包
servlet包
…
以后
util项目
domain项目
servlet项目
只是举例,以后并不这样分层
将三个项目分别放到三个服务器,浏览器首先访问servlet服务器,因为servlet需要谁用到domain项目和util项目中的内容,只能通过跨域进行访问