Web核心技术之Ajax异步请求,前端ndk开发书籍

35 阅读15分钟

​ 浏览器页面在发送请求给服务器,在服务器处理请求的过程中,浏览器页面不能做其他的操作。只能等到服务器响应结束后才能,浏览器页面才能继续做其他的操作。

  • 异步发送请求过程如下

浏览器页面发送请求给服务器,在服务器处理请求的过程中,浏览器页面还可以做其他的操作。

3.2 快速入门

3.2.1 服务端实现

在项目的创建 com.ligong.web.servlet ,并在该包下创建名为 AjaxServlet 的servlet

@WebServlet("/ajaxServlet")

public class AjaxServlet extends HttpServlet {

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

//1. 响应数据

response.getWriter().write("hello ajax~");

}

@Override

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

this.doGet(request, response);

}

}

3.2.2 客户端实现

webapp 下创建名为 01-ajax-demo1.html 的页面,在该页面书写 ajax 代码

  • 创建核心对象,不同的浏览器创建的对象是不同的

var xhttp;

if (window.XMLHttpRequest) {

xhttp = new XMLHttpRequest();

} else {

// code for IE6, IE5

xhttp = new ActiveXObject("Microsoft.XMLHTTP");

}

  • 发送请求

//建立连接

xhttp.open("GET", "http://localhost:8080/ajax-demo/ajaxServlet");

//发送请求

xhttp.send();

  • 获取响应

xhttp.onreadystatechange = function() {

if (this.readyState == 4 && this.status == 200) {

// 通过 this.responseText 可以获取到服务端响应的数据

alert(this.responseText);

}

};

完整代码如下:

Title

3.2.3 测试

在浏览器地址栏输入 http://localhost:8080/ajax-demo/01-ajax-demo1.html ,在 01-ajax-demo1.html加载的时候就会发送 ajax 请求,效果如下

我们可以通过 开发者模式 查看发送的 AJAX 请求。在浏览器上按 F12 快捷键

这个是查看所有的请求,如果我们只是想看 异步请求的话,点击上图中 All 旁边的 XHR,会发现只展示 Type 是 xhr 的请求。如下图:

3.3 案例

需求:在完成用户注册时,当用户名输入框失去焦点时,校验用户名是否在数据库已存在

3.3.1 分析

  • 前端完成的逻辑
  1. 给用户名输入框绑定光标失去焦点事件 onblur

  2. 发送 ajax请求,携带username参数

  3. 处理响应:是否显示提示信息

  • 后端完成的逻辑
  1. 接收用户名

  2. 调用service查询User。此案例是为了演示前后端异步交互,所以此处我们不做业务逻辑处理

  3. 返回标记

整体流程如下:

3.3.2 后端实现

com.ligong.web.servlet 包中定义名为 SelectUserServlet 的servlet。代码如下:

@WebServlet("/selectUserServlet")

public class SelectUserServlet extends HttpServlet {

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

//1. 接收用户名

String username = request.getParameter("username");

//2. 调用service查询User对象,此处不进行业务逻辑处理,直接给 flag 赋值为 true,表明用户名占用

boolean flag = true;

//3. 响应标记

response.getWriter().write("" + flag);

}

@Override

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

this.doGet(request, response);

}

}

3.3.3 前端实现

04-资料\1. 验证用户名案例\1. 静态页面 下的文件整体拷贝到项目下 webapp 下。并在 register.html 页面的 body 结束标签前编写 script 标签,在该标签中实现如下逻辑

第一步:给用户名输入框绑定光标失去焦点事件 onblur

//1. 给用户名输入框绑定 失去焦点事件

document.getElementById("username").onblur = function () {

}

第二步:发送 ajax请求,携带username参数

第一步 绑定的匿名函数中书写发送 ajax 请求的代码

//2. 发送ajax请求

//2.1. 创建核心对象

var xhttp;

if (window.XMLHttpRequest) {

xhttp = new XMLHttpRequest();

} else {

// code for IE6, IE5

xhttp = new ActiveXObject("Microsoft.XMLHTTP");

}

//2.2. 发送请求

xhttp.open("GET", "http://localhost:8080/ajax-demo/selectUserServlet);

xhttp.send();

//2.3. 获取响应

xhttp.onreadystatechange = function() {

if (this.readyState == 4 && this.status == 200) {

//处理响应的结果

}

};

由于我们发送的是 GET 请求,所以需要在 URL 后拼接从输入框获取的用户名数据。而我们在 第一步 绑定的匿名函数中通过以下代码可以获取用户名数据

// 获取用户名的值

var username = this.value; //this : 给谁绑定的事件,this就代表谁

而携带数据需要将 URL 修改为:

xhttp.open("GET", "http://localhost:8080/ajax-demo/selectUserServlet?username="+username);

第三步:处理响应:是否显示提示信息

this.readyState == 4 && this.status == 200 条件满足时,说明已经成功响应数据了。

此时需要判断响应的数据是否是 “true” 字符串,如果是说明用户名已经占用给出错误提示;如果不是说明用户名未被占用清除错误提示。代码如下

//判断

if(this.responseText == "true"){

//用户名存在,显示提示信息

document.getElementById("username_err").style.display = '';

}else {

//用户名不存在 ,清楚提示信息

document.getElementById("username_err").style.display = 'none';

}

综上所述,前端完成代码如下:

//1. 给用户名输入框绑定 失去焦点事件

document.getElementById("username").onblur = function () {

//2. 发送ajax请求

// 获取用户名的值

var username = this.value;

//2.1. 创建核心对象

var xhttp;

if (window.XMLHttpRequest) {

xhttp = new XMLHttpRequest();

} else {

// code for IE6, IE5

xhttp = new ActiveXObject("Microsoft.XMLHTTP");

}

//2.2. 发送请求

xhttp.open("GET", "http://localhost:8080/ajax-demo/selectUserServlet?username="+username);

xhttp.send();

//2.3. 获取响应

xhttp.onreadystatechange = function() {

if (this.readyState == 4 && this.status == 200) {

//alert(this.responseText);

//判断

if(this.responseText == "true"){

//用户名存在,显示提示信息

document.getElementById("username_err").style.display = '';

}else {

//用户名不存在 ,清楚提示信息

document.getElementById("username_err").style.display = 'none';

}

}

};

}

4,axios


Axios 对原生的AJAX进行封装,简化书写。

Axios官网是:https://www.axios-http.cn

4.1 基本使用

axios 使用是比较简单的,分为以下两步:

  • 引入 axios 的 js 文件
  • 使用axios 发送请求,并获取响应结果

  • 发送 get 请求

axios({

method:"get",

url:"http://localhost:8080/ajax-demo1/aJAXDemo1?username=zhangsan"

}).then(function (resp){

alert(resp.data);

})

  • 发送 post 请求

axios({

method:"post",

url:"http://localhost:8080/ajax-demo1/aJAXDemo1",

data:"username=zhangsan"

}).then(function (resp){

alert(resp.data);

});

axios() 是用来发送异步请求的,小括号中使用 js 对象传递请求相关的参数:

  • method 属性:用来设置请求方式的。取值为 get 或者 post

  • url 属性:用来书写请求的资源路径。如果是 get 请求,需要将请求参数拼接到路径的后面,格式为: url?参数名=参数值&参数名2=参数值2

  • data 属性:作为请求体被发送的数据。也就是说如果是 post 请求的话,数据需要作为 data 属性的值。

then() 需要传递一个匿名函数。我们将 then() 中传递的匿名函数称为 回调函数,意思是该匿名函数在发送请求时不会被调用,而是在成功响应后调用的函数。而该回调函数中的 resp 参数是对响应的数据进行封装的对象,通过 resp.data 可以获取到响应的数据。

4.2 快速入门

4.2.1 后端实现

定义一个用于接收请求的servlet,代码如下:

@WebServlet("/axiosServlet")

public class AxiosServlet extends HttpServlet {

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

System.out.println("get...");

//1. 接收请求参数

String username = request.getParameter("username");

System.out.println(username);

//2. 响应数据

response.getWriter().write("hello Axios~");

}

@Override

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

System.out.println("post...");

this.doGet(request, response);

}

}

4.2.2 前端实现

  • 引入 js 文件
  • 发送 ajax 请求

  • get 请求

axios({

method:"get",

url:"http://localhost:8080/ajax-demo/axiosServlet?username=zhangsan"

}).then(function (resp) {

alert(resp.data);

})

  • post 请求

axios({

method:"post",

url:"http://localhost:8080/ajax-demo/axiosServlet",

data:"username=zhangsan"

}).then(function (resp) {

alert(resp.data);

})

整体页面代码如下:

Title

4.3 请求方法别名

为了方便起见, Axios 已经为所有支持的请求方法提供了别名。如下:

  • get 请求 : axios.get(url[,config])

  • delete 请求 : axios.delete(url[,config])

  • head 请求 : axios.head(url[,config])

  • options 请求 : axios.option(url[,config])

  • post 请求:axios.post(url[,data[,config])

  • put 请求:axios.put(url[,data[,config])

  • patch 请求:axios.patch(url[,data[,config])

而我们只关注 get 请求和 post 请求。

入门案例中的 get 请求代码可以改为如下:

axios.get("http://localhost:8080/ajax-demo/axiosServlet?username=zhangsan").then(function (resp) {

alert(resp.data);

});

入门案例中的 post 请求代码可以改为如下:

axios.post("http://localhost:8080/ajax-demo/axiosServlet","username=zhangsan").then(function (resp) {

alert(resp.data);

})

5,JSON


5.1 概述

概念:JavaScript Object Notation。JavaScript 对象表示法.

如下是 JavaScript 对象的定义格式:

{

name:"zhangsan",

age:23,

city:"北京"

}

接下来我们再看看 JSON 的格式:

{

"name":"zhangsan",

"age":23,

"city":"北京"

}

通过上面 js 对象格式和 json 格式进行对比,发现两个格式特别像。只不过 js 对象中的属性名可以使用引号(可以是单引号,也可以是双引号);而 json 格式中的键要求必须使用双引号括起来,这是 json 格式的规定。json 格式的数据有什么作用呢?

作用:由于其语法格式简单,层次结构鲜明,现多用于作为数据载体,在网络中进行数据传输。如下图所示就是服务端给浏览器响应的数据,这个数据比较简单,如果现需要将 JAVA 对象中封装的数据响应回给浏览器的话,应该以何种数据传输呢?

大家还记得 ajax 的概念吗? 是 异步的 JavaScript 和 xml。这里的 xml就是以前进行数据传递的方式,如下:

张三

23

北京

再看 json 描述以上数据的写法:

{

"name":"张三",

"age":23,

"city":"北京"

}

上面两种格式进行对比后就会发现 json 格式数据的简单,以及所占的字节数少等优点。

5.2 JSON 基础语法

5.2.1 定义格式

JSON 本质就是一个字符串,但是该字符串内容是有一定的格式要求的。 定义格式如下:

var 变量名 = '{"key":value,"key":value,...}';

JSON 串的键要求必须使用双引号括起来,而值根据要表示的类型确定。value 的数据类型分为如下

  • 数字(整数或浮点数)

  • 字符串(使用双引号括起来)

  • 逻辑值(true或者false)

  • 数组(在方括号中)

  • 对象(在花括号中)

  • null

示例:

var jsonStr = '{"name":"zhangsan","age":23,"addr":["北京","上海","西安"]}'

5.2.2 代码演示

创建一个页面,在该页面的 <script> 标签中定义json字符串

Title

通过浏览器打开,页面效果如下图所示

现在我们需要获取到该 JSON 串中的 name 属性值,应该怎么处理呢?

如果它是一个 js 对象,我们就可以通过 js对象.属性名 的方式来获取数据。JS 提供了一个对象 JSON ,该对象有如下两个方法:

  • parse(str) :将 JSON串转换为 js 对象。使用方式是: var jsObject = JSON.parse(jsonStr);

  • stringify(obj) :将 js 对象转换为 JSON 串。使用方式是:var jsonStr = JSON.stringify(jsObject)

代码演示:

Title

5.2.3 发送异步请求携带参数

后面我们使用 axios 发送请求时,如果要携带复杂的数据时都会以 JSON 格式进行传递,如下

axios({

method:"post",

url:"http://localhost:8080/ajax-demo/axiosServlet",

data:"username=zhangsan"

}).then(function (resp) {

alert(resp.data);

})

请求参数不可能由我们自己拼接字符串吧?肯定不用,可以提前定义一个 js 对象,用来封装需要提交的参数,然后使用 JSON.stringify(js对象) 转换为 JSON 串,再将该 JSON 串作为 axiosdata 属性值进行请求参数的提交。如下:

var jsObject = {name:"张三"};

axios({

method:"post",

url:"http://localhost:8080/ajax-demo/axiosServlet",

data: JSON.stringify(jsObject)

}).then(function (resp) {

alert(resp.data);

})

axios 是一个很强大的工具。我们只需要将需要提交的参数封装成 js 对象,并将该 js 对象作为 axiosdata 属性值进行,它会自动将 js 对象转换为 JSON 串进行提交。如下:

var jsObject = {name:"张三"};

axios({

method:"post",

url:"http://localhost:8080/ajax-demo/axiosServlet",

data:jsObject //这里 axios 会将该js对象转换为 json 串的

}).then(function (resp) {

alert(resp.data);

})

注意:

  • js 提供的 JSON 对象我们只需要了解一下即可。因为 axios 会自动对 js 对象和 JSON 串进行想换转换。
  • 发送异步请求时,如果请求参数是 JSON 格式,那请求方式必须是 POST。因为 JSON 串需要放在请求体中。

5.3 JSON串和Java对象的相互转换

学习完 json 后,接下来聊聊 json 的作用。以后我们会以 json 格式的数据进行前后端交互。前端发送请求时,如果是复杂的数据就会以 json 提交给后端;而后端如果需要响应一些复杂的数据时,也需要以 json 格式将数据响应回给浏览器。

在后端我们就需要重点学习以下两部分操作:

  • 请求数据:JSON字符串转为Java对象

  • 响应数据:Java对象转为JSON字符串

接下来给大家介绍一套 API,可以实现上面两部分操作。这套 API 就是 jackson

5.3.1 Jackson 概述

Jackson 是一个 Java 的用来处理 JSON 格式数据的类库,性能非常好。

5.3.2 Jackson 使用

jaskson 使用也是比较简单的,分为以下四步完成

  1. 导入坐标

com.fasterxml.jackson.core

jackson-databind

2.9.1

  1. 创建ObjectMapper对象

bjectMapper mapper = new ObjectMapper();

  1. Java对象转JSON

String str = mapper.writeValueAsString(user);

将 Java 对象转换为 JSON 串,只需要使用 mapper 提供的writeValueAsString方法即可。

  1. JSON字符串转Java对象

User object = mapper.readValue(str, User.class);

将 json 转换为 Java 对象,只需要使用mapper 提供的readValue方法即可。

5.3.3 代码演示

  • 引入坐标

  • 创建一个类,专门用来测试 Java 对象和 JSON 串的相互转换,代码如下:

public class JacksonDemo {

public static void main(String[] args) {

//1 创建ObjectMapper对象

ObjectMapper mapper = new ObjectMapper();

User user = new User(1, "zhangsan", "123");

// 把对象转换成json

String str = mapper.writeValueAsString(user);

System.out.println(str);

// 字符串

String content = "{"id":1,"username":"zhangsan","password":"123"}";

User object = mapper.readValue(content, User.class);

System.out.println(object);

}

}

5.4 服务器获取json数据

学习完 json 后,接下来聊聊 json 的作用

  • 获取请求参数

由于前端提交的是 json 格式的数据,所以我们不能使用 request.getParameter() 方法获取请求参数。

通过获取数据流的方式来获取。

//中文请求乱码

request.setCharacterEncoding("utf-8");

// 1 获取数据流

BufferedReader br = request.getReader();

String json = br.readLine();

6,案例


6.1 需求

使用Axios + JSON 完成品牌列表数据查询和添加。页面效果还是下图所示:

6.2 查询所有功能

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r4FKNF2p-1642766224444)(assets/image-20210831085332612.png)]

如上图所示就该功能的整体流程。前后端需以 JSON 格式进行数据的传递;由于此功能是查询所有的功能,前端发送 ajax 请求不需要携带参数,而后端响应数据需以如下格式的 json 数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BCts8EMk-1642766224445)(assets/image-20210831090839336.png)]

6.2.1 环境准备

02-AJAX\04-资料\3. 品牌列表案例\初始工程 下的 brand-demo 工程拷贝到我们自己 工作空间 ,然后再将项目导入到我们自己的 Idea 中。工程目录结构如下:

注意:

  • 在给定的原始工程中已经给定一些代码。而在此案例中我们只关注前后端交互代码实现

  • 要根据自己的数据库环境去修改连接数据库的信息,在 mybatis-config.xml 核心配置文件中修改

6.2.2 后端实现

com.ligong.web 包下创建名为 SelectAllServletservlet,具体的逻辑如下:

  • 调用 service 的 selectAll() 方法进行查询所有的逻辑处理

  • 将查询到的集合数据转换为 json 数据。我们将此过程称为 序列化;如果是将 json 数据转换为 Java 对象,我们称之为 反序列化

  • 将 json 数据响应回给浏览器。这里一定要设置响应数据的类型及字符集 response.setContentType("text/json;charset=utf-8");

SelectAllServlet 代码如下:

@WebServlet("/selectAllServlet")

public class SelectAllServlet extends HttpServlet {

private BrandService brandService = new BrandService();

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

//1. 调用Service查询

List brands = brandService.selectAll();

//2 把集合转换成json

ObjectMapper mapper = new ObjectMapper();

String json = mapper.writeValueAsString(brands);

//3. 响应数据 application/json text/json

response.setContentType("text/json;charset=utf-8");

response.getWriter().write(jsonString);

}

@Override

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

this.doGet(request, response);

}

}

6.2.3 前端实现

  1. 引入 js 文件

brand.html 页面引入 axios 的 js 文件

  1. 绑定 页面加载完毕 事件

brand.html 页面绑定加载完毕事件,该事件是在页面加载完毕后被触发,代码如下

window.onload = function() {

}

  1. 发送异步请求

在页面加载完毕事件绑定的匿名函数中发送异步请求,代码如下:

//2. 发送ajax请求

axios({

method:"get",

url:"http://localhost:8080/brand-demo/selectAllServlet"

}).then(resp => {

});

  1. 处理响应数据

then 中的回调函数中通过 resp.data 可以获取响应回来的数据,而数据格式如下

总结一下

面试前要精心做好准备,简历上写的知识点和原理都需要准备好,项目上多想想难点和亮点,这是面试时能和别人不一样的地方。

还有就是表现出自己的谦虚好学,以及对于未来持续进阶的规划,企业招人更偏爱稳定的人。

万事开头难,但是程序员这一条路坚持几年后发展空间还是非常大的,一切重在坚持。

为了帮助大家更好更高效的准备面试,特别整理了《前端工程师面试手册》电子稿文件。

前端面试题汇总

开源分享:docs.qq.com/doc/DSmRnRG…