第一节 Ajax概述
1、概述
- 概念: Asynchronous JavaScript And XML,
异步
的JavaScript和XML。 - 作用:
- 数据交换:通过Ajax可以给服务器发送请求,并获取服务器响应的数据。
- 异步交互:可以在
不重新加载整个页面
的情况下,与服务器交换数据并更新部分网页
的技术,如:搜索联想、用户名是否可用的校验等等。
2、页面渲染方式
2.1、服务器端渲染
2.2、Ajax渲染(局部更新)
3、前后端分离
彻底舍弃服务器端渲染,数据全部通过Ajax方式以JSON格式来传递。
4、同步与异步
Ajax本身就是Asynchronous JavaScript And XML的缩写,直译为:异步的JavaScript和XML。在实际应用中Ajax指的是:不刷新浏览器窗口,不做页面跳转,局部更新页面内容
的技术。
『同步』
和『异步』
是一对相对的概念,那么什么是同步,什么是异步呢?
4.1、同步
多个操作按顺序执行
,前面的操作没有完成,后面的操作就必须等待
。所以同步操作通常是串行
的。
4.2、异步
多个操作相继开始并发执行
,即使开始的先后顺序不同,但是由于它们各自是在自己独立的进程或线程中
完成,所以互不干扰,谁也不用等谁
。
5、Axios简介
使用原生的JavaScript程序执行Ajax极其繁琐,所以一定要使用框架来完成。而Axios就是目前最流行的前端Ajax框架。
Axios官网:http://www.axios-js.com/
使用Axios和使用Vue一样,导入对应的*.js文件
即可。官方提供的script标签引入方式为:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
我们可以把这个axios.min.js文件下载下来保存到本地来使用。
第二节 Axios基本用法
1、在前端页面引入开发环境
<!--引入vue.js文件-->
<script language="JavaScript" src="script/vue.js"></script>
<!--引入axios.min.js文件-->
<script language="JavaScript" src="script/axios.min.js"></script>
2、入门案例(黑马)
步骤:
- 引入Axios的js文件:略
- 使用Axios发送请求,并获取响应结果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ajax-Axios</title>
<script src="script/axios.min.js"></script>
</head>
<body>
<input type="button" value="获取数据GET" onclick="get()">
<input type="button" value="删除数据POST" onclick="post()">
</body>
<script>
function get(){
//通过axios发送异步请求-get,参数拼接在url地址中进行传递
//原始写法:
// axios({
// method: "get",
// url: "http://yapi.smart-xwork.cn/mock/169327/emp/list" //这是黑马提供的一个服务器地址是个json对象
// }).then(function (result){
// console.log(result.data);//获取响应的结果
// })
//原始写法-箭头函数
// axios({
// method: "get",
// url: "http://yapi.smart-xwork.cn/mock/169327/emp/list"
// }).then(result => {
// console.log(result.data);
// })
//简化写法:
axios.get("http://yapi.smart-xwork.cn/mock/169327/emp/list").then(function (result){
console.log(result.data);//获取响应的结果
})
//简化写法-箭头函数
// axios.get("http://yapi.smart-xwork.cn/mock/169327/emp/list").then(result => {
// console.log(result.data);
// })
}
function post(){
//通过axios发送异步请求-post
//原始写法:
// axios({
// method: "post",
// url: "http://yapi.smart-xwork.cn/mock/169327/emp/deleteById",
// data: "id=1"
// }).then(function (result){
// console.log(result.data);//获取响应的结果
// })
//原始写法-箭头函数
// axios({
// method: "post",
// url: "http://yapi.smart-xwork.cn/mock/169327/emp/deleteById",
// data: "id=1"
// }).then(result => {
// console.log(result.data);
// })
//简化写法:
axios.post("http://yapi.smart-xwork.cn/mock/169327/emp/deleteById","id=1").then(function (result){
console.log(result.data);//获取响应的结果
})
//简化写法-箭头函数
// axios.post("http://yapi.smart-xwork.cn/mock/169327/emp/deleteById","id=1").then(result => {
// console.log(result.data);
// })
}
</script>
</html>
- 测试:
- YAPI所生成的MocK测试数据的地址,是个json对象
- 可以看到正确的获取到了响应的数据
- YAPI所生成的MocK测试数据的地址,是个json对象
- 简化写法:
3、Vue+Axios完成数据的动态加载展示(黑马)
需求:
-
数据准备的url:YAPI所生成的MocK测试数据的地址
http://yapi.smart-xwork.cn/mock/169327/emp/list
-
在页面加载完成后,
自动发送
异步请求,加载数据,渲染展示页面- (性别:1代表男,2代表女)。
- (性别:1代表男,2代表女)。
测试:
- html代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ajax-Axios-案例</title>
<script src="script/axios.min.js"></script>
<script src="script/vue.js"></script>
</head>
<body>
<div id="app">
<table border="1" cellspacing="0" width="60%">
<tr>
<th>编号</th>
<th>姓名</th>
<th>图像</th>
<th>性别</th>
<th>职位</th>
<th>入职日期</th>
<th>最后操作时间</th>
</tr>
<tr align="center" v-for="(emp,index) in emps">
<!--绑定文本-->
<!--编号要求从1开始,索引从0开始,所以加上iddex+1表示编号为从1开始-->
<td>{{index + 1}}</td>
<td>{{emp.name}}</td>
<!--绑定属性:-->
<td>
<img :src="emp.image" width="70px" height="50px">
</td>
<td>
<span v-if="emp.gender == 1">男</span>
<span v-if="emp.gender == 2">女</span>
</td>
<td>{{emp.job}}</td>
<td>{{emp.entrydate}}</td>
<td>{{emp.updatetime}}</td>
</tr>
</table>
</div>
</body>
<script>
var vue = new Vue({
el: "#app",
data: {
emps:[]
},
//页面加载完成后自动执行:vue中的钩子函数mounted,他会在页面加载完成后自动执行
mounted () {
//发送异步请求,加载数据
//方式一:箭头函数
axios.get("http://yapi.smart-xwork.cn/mock/169327/emp/list").then(result => {
//result.data:获取到响应的数据,此案例返回的是个json对象
//result.data.data:获取到json对象的data属性,此属性的值为一个数组,里面封装的是一个个的对象。
//如何把获取到的data属性中存的数组,和html标签绑定在一块呢??
// 答:只需要把值赋值给vue当中的一个数据模型emps就可以了。
// this:代表当前的vue对象
// this.emps:代表为当前vue对象中的emps这个数据模型赋值。
//之后只需要遍历数据模型中的数组获取每个对象,然后通过对象.属性获取即可。
this.emps = result.data.data;
})
//方式二:普通函数
//注意:箭头函数this代表当前对象,而在普通函数中只能使用vue对象名来调用对象属性
// axios.get("http://yapi.smart-xwork.cn/mock/169327/emp/list").then(function(result){
// vue.emps = result.data.data;
// })
}
});
</script>
</html>
- 效果:
4、发送普通请求参数
2.1、基本格式
客户端向服务器端异步发送普通参数值:使用params
表示
- 基本格式: axios().then().catch()
- 示例:
axios({ //括号里面是一个对象
method:"POST",
url:"....",
params:{
uname:"lina",
pwd:"ok"
}
})
//成功响应时执行的回调:then()
// value就是成功时服务器端返回的响应数据对象
// value.data通过对象调用data属性,就可以获取到服务器响应体内容
.then(function(value){})
//有异常时执行的回调catch():
// reason就是出错时服务器端返回的响应数据
// reason.response在服务器端处理请求失败后,获取axios封装的JSON格式的响应数据对象
// reason.response.data可以获取到响应的内容
// reason.response.status在服务器端处理请求失败后,获取响应状态码
// reason.response.statusText在服务器端处理请求失败后,获取响应状态说明文本
// reason.message / reason.stack 可以查看错误的信息
.catch(function(reason){});
2.2、前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--引入vue.js文件-->
<script language="JavaScript" src="script/vue.js"></script>
<!--引入axios.min.js文件-->
<script language="JavaScript" src="script/axios.min.js"></script>
<script language="JavaScript">
window.onload=function(){//文档就绪事件函数
var vue = new Vue({
el:"#div0",
data:{
uname:"lina",
pwd:"ok"
},
methods:{
axios01:function(){
axios({
method:"post",
url:"http://localhost:8080/Vue/axios01.do",
params:{
//注意:不能使用this.uname只能使用vue.uname,因为已经进入到axios中了,this代表的是axios
// 里面的属性,想要使用date中的属性只能通过vue来调用。
uname:vue.uname,
pwd:vue.pwd
}
})
.then(function (value) {
console.log(value);
})
.catch(function (reason) {
console.log(reason);
});
}
}
});
}
</script>
</head>
<body>
<div id="div0">
uname:<input type="text" v-model="uname"/><br/>
pwd:<input type="text" v-model="pwd"/><br/>
<input type="button" @click="axios01" value="发送一个带普通请求参数值的异步请求"/>
</div>
</body>
</html>
2.3、后端代码
package axios;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/axios01.do")//Servlet3.0使用注解代替原先的xml方式配置路径
public class Axios01Servlet extends HttpServlet {
private static final long serialVersionUID = -8499971529938553156L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String uname = request.getParameter("uname");
String pwd = request.getParameter("pwd");
System.out.println("uname = " + uname);
System.out.println("pwd = " + pwd);
response.setCharacterEncoding("utf-8");
//设置返回的类型是普通文本
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.write(uname+"_"+pwd);
// throw new NullPointerException("这里故意抛出一个空指针异常....");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
P.S.:由于我们不需要Thymeleaf了,所以ModelBaseServlet可以跳过ViewBaseServlet直接继承HttpServlet。
2.4、运行测试
说明:启动Tomact,首先访问到demo10.html页面,在页面点击按钮执行点击事件,通过axios方式post请求。
可以看到在控制层方法中获取到了请求参数:
请求参数:所有请求参数都被放到URL地址后面了,哪怕我们现在用的是POST请求方式。
响应的内容:
2.5、DeBug查看成功响应的对象value结构
说明:使用js的DeBug调试,查看成功响应时执行的回调函数中的value参数值:
可以看到:data数据在value中
属性名 | 作用 |
---|---|
config | 调用axios(config对象)方法时传入的JSON对象 |
data | 服务器端返回的响应体数据 |
headers | 响应消息头 |
request | 原生JavaScript执行Ajax操作时使用的XMLHttpRequest |
status | 响应状态码 |
statusText | 响应状态码的说明文本 |
2.6、DeBug查看失败响应的对象reson结构
说明:使用js的DeBug调试,查看失败响应时执行的回调函数中的reson参数值:
可以看到:data数据在reson下面的response中。
可以看到:response对象的结构还是和then()函数传入的回调函数中的response是一样的:
回调函数:开发人员声明,但是调用时交给系统来调用。像单击响应函数、then()、catch()里面传入的都是回调函数。回调函数是相对于普通函数来说的,普通函数就是开发人员自己声明,自己调用:
普通函数:
function sum(a, b) {
return a+b;
}
var result = sum(3, 2);
console.log("result="+result);
5、发送请求体JSON
5.1、JSON概述
什么是JSON:
- JSON是一种数据格式
- XML也是一种数据格式
JSON格式表示两个学员信息的代码如下:
//JSON表达数据更简洁,更能够节约网络带宽
[{sid:"s001",age:18},{sid:"s002",age:19}]
XML格式表示两个学员信息的代码如下:
<students>
<student sid="s001">
<sname>jim</sname>
<age>18</age>
</student>
<student sid="s002">
<sname>tom</sname>
<age>19</age>
</student>
</students>
5.2、注意事项
-
客户端 axios里面的params需要修改成:
data:
-
服务器获取参数值不再是
request.getParameter()...
而是:
StringBuffer stringBuffer = new StringBuffer(“”);
BufferedReader bufferedReader = request.getReader();
String str = null ;
while((str=bufferedReader.readLine())!=null){
stringBuffer.append(str);
}
str = stringBuffer.toString() ; -
我们会发现 str的内容如下:
{"uname":"lina","pwd":"ok"}
5.3、前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--引入vue.js文件-->
<script language="JavaScript" src="script/vue.js"></script>
<!--引入axios.min.js文件-->
<script language="JavaScript" src="script/axios.min.js"></script>
<script language="JavaScript">
window.onload=function(){//文档就绪事件函数
var vue = new Vue({
el:"#div0",
data:{
uname:"lina",
pwd:"ok"
},
methods:{
axios02:function(){
axios({
method:"post",
url:"http://localhost:8080/Vue/axios02.do",
data:{
//注意:不能使用this.uname使能使用vue.uname,因为已经进入到axios中了,this代表的是axios
// 里面的属性,想要使用date中的属性只能通过vue来调用。
uname:vue.uname,
pwd:vue.pwd
}
})
.then(function (value) {
console.log(value);
})
.catch(function (reason) {
console.log(reason);
});
}
}
});
}
</script>
</head>
<body>
<div id="div0">
uname:<input type="text" v-model="uname"/><br/>
pwd:<input type="text" v-model="pwd"/><br/>
<input type="button" @click="axios02" value="发送JSON格式的参数值的异步请求"/>
</div>
</body>
</html>
5.4、后端代码
1) 加入Gson包
Gson是Google研发的一款非常优秀的JSON数据解析和生成工具
,它可以帮助我们将数据在JSON字符串和Java对象之间互相转换。
将jar包添加到类路径:Add as Library
2) User实体类
作用:封装json字符串转化为一个java对象后的数据。
package pojo;
public class User {
private String uname ;
private String pwd ;
public User(){}
public User(String uname, String pwd) {
this.uname = uname;
this.pwd = pwd;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"uname='" + uname + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
3) Servlet代码
package axios;
import com.google.gson.Gson;
import pojo.User;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
@WebServlet("/axios02.do")//Servlet3.0使用注解代替原先的xml方式配置路径
public class Axios02Servlet extends HttpServlet {
private static final long serialVersionUID = -8499971529938553156L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.创建StringBuffer对象来累加存储从请求体中读取到的每一行
StringBuffer stringBuffer = new StringBuffer("");
// 2.由于请求体数据有可能很大,所以Servlet标准在设计API的时候要求我们通过输入流来读取
BufferedReader bufferedReader = request.getReader();
// 3.声明临时变量
String str = null ;
// 4.循环读取
while((str=bufferedReader.readLine())!=null){
stringBuffer.append(str);
}
// 5.关闭流
bufferedReader.close();
// 6.累加的结果就是整个请求体
str = stringBuffer.toString() ;
System.out.println(str);// {"uname":"lina","pwd":"ok"} 获取到的是json字符串类型的数据
// 7.后台操作的是java对象,所以我们需要把json字符串转化为java对象
// 创建Gson对象:2种
// Gson gson =new GsonBuilder().create(); 这种方式功能更强大,eg:可以做格式化
Gson gson =new Gson();
// Gson有两个API:
// 1).fromJson(string,T) 将字符串转化成java object
// 2).toJson(java Object) 将java object转化成json字符串,这样才能响应给客户端
User user = gson.fromJson(str, User.class);
System.out.println(user);//User{uname='lina', pwd='ok'}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
P.S.:看着很麻烦是吧?别担心,将来我们有了SpringMVC之后,一个@RequestBody注解就能够搞定,非常方便!
4) 运行测试
P.S.:Chrome浏览器中将『请求负载』显示为英文:『Request Payload』。
6、服务器端返回JSON数据
说明:服务器端给客户端响应JSON格式的字符串,然后客户端需要将字符串转化成json对象,使用axios会自动把服务端响应给客户端的json字符串转化为json对象。
6.1、前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--引入vue.js文件-->
<script language="JavaScript" src="script/vue.js"></script>
<!--引入axios.min.js文件-->
<script language="JavaScript" src="script/axios.min.js"></script>
<script language="JavaScript">
window.onload=function(){//文档就绪事件函数
var vue = new Vue({
el:"#div0",
data:{
uname:"lina",
pwd:"ok"
},
methods:{
axios03:function(){
axios({
method:"post",
url:"http://localhost:8080/Vue/axios03.do",
data:{
//注意:不能使用this.uname使能使用vue.uname,因为已经进入到axios中了,this代表的是axios
// 里面的属性,想要使用date中的属性只能通过vue来调用。
uname:vue.uname,
pwd:vue.pwd
}
})
.then(function (value) {
var data = value.data;
// data对应的数据:{uname:"鸠摩智",pwd:"ok"} ---->json对象
// 可以看出:会自动把服务端传来的json字符串转化为json对象,所以可以直接调用它的属性
vue.uname=data.uname;
vue.pwd=data.pwd;
//此处value中的data返回的是 js object,因此可以直接点出属性
//如果我们获取的是一个字符串: "{uname:\"鸠摩智\",pwd:\"ok\"}"
//js语言中 也有字符串和js对象之间互转的API
//string JSON.stringify(object) object->string
//object JSON.parse(string) string->object
})
.catch(function (reason) {
console.log(reason);
});
}
}
});
}
</script>
</head>
<body>
<div id="div0">
uname:<input type="text" v-model="uname"/><br/>
pwd:<input type="text" v-model="pwd"/><br/>
<input type="button" @click="axios03" value="发送JSON格式的参数值的异步请求,服务器端给客户端响应JSON格式的字符串"/>
</div>
</body>
</html>
6.2、后端代码
1) 加入Gson包
仍然需要Gson支持,不用多说
2) User实体类
略,这个地方是测试响应后的数据,没用到这个类,只不过现在页面流程是先发送请求在响应给页面数据,发送请求时json字符串转化为java对象时用到了。
3) Servlet代码
package axios;
import com.google.gson.Gson;
import pojo.User;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
@WebServlet("/axios03.do")//Servlet3.0使用注解代替原先的xml方式配置路径
public class Axios03Servlet extends HttpServlet {
private static final long serialVersionUID = -8499971529938553156L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.创建StringBuffer对象来累加存储从请求体中读取到的每一行
StringBuffer stringBuffer = new StringBuffer("");
// 2.由于请求体数据有可能很大,所以Servlet标准在设计API的时候要求我们通过输入流来读取
BufferedReader bufferedReader = request.getReader();
// 3.声明临时变量
String str = null ;
// 4.循环读取
while((str=bufferedReader.readLine())!=null){
stringBuffer.append(str);
}
// 5.关闭流
bufferedReader.close();
// 6.累加的结果就是整个请求体
str = stringBuffer.toString() ;
System.out.println(str);// {"uname":"lina","pwd":"ok"} 获取到的是json字符串类型的数据
// 7.后台操作的是java对象,所以我们需要把json字符串转化为java对象
// 创建Gson对象:2种
// Gson gson =new GsonBuilder().create(); 这种方式功能更强大,eg:可以做格式化
Gson gson =new Gson();
// Gson有两个API:
// 1).fromJson(string,T) 将字符串转化成java object
// 2).toJson(java Object) 将java object转化成json字符串,这样才能响应给客户端
User user = gson.fromJson(str, User.class);
user.setUname("鸠摩智");
user.setPwd("123456");
System.out.println(user);//User{uname='lina', pwd='ok'}
//假设user是从数据库查询出来的,现在需要将其转化成json格式的字符串,然后响应给客户端
String userJsonStr = gson.toJson(user);//注意:转化后的是一个json字符串
response.setCharacterEncoding("UTF-8");
//MIME-TYPE 设置返回的类型是json
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(userJsonStr);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
4) 运行测试
流程:页面发送请求携带json格式的参数,之后在服务端获取并测试json字符串和java对象的转化,之修改下User实体类的数据便于看到页面效果,把json对象转化为json字符串返回给页面,客户端使用axios会自动把接收的json字符串转化为json对象,直接取值即可。把取出的值复制给了uname、pwd,这2个属性又绑定了文本框,所以点击提交按钮值会发生变化。
点击按钮前:
点击按钮后: