JavaWeb 学习笔记 8:AJAX

JavaWeb 学习笔记 8:AJAX

AJAX(Asynchronous JavaScript And XML,异步 js 和 XML)是一种用 js 代码异步(或同步)的方式请求服务端数据,并在页面显示或加载的技术。

1.快速入门

先看如何用纯 js 的方式使用 AJAX:

定义一个用于响应 AJAX 请求的 Servlet:

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.getWriter().println("Hello World!");}
}

定义一个 html 页面:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<button onclick="doAjaxRequest()">send</button>
</body>
<script>function doAjaxRequest(){// 创建 XMLHttpRequest 对象const xhttp = new XMLHttpRequest();// 定义回调函数xhttp.onreadystatechange = function() {if (this.readyState == 4 && this.status == 200) {let result = this.responseText;console.log(result);}};// 发送请求xhttp.open("GET", "http://localhost:8080/ajax-demo/hello", true);xhttp.send();}
</script>
</html>

js 方法doAjaxRequest负责创建一个 XMLHttpRequest 对象,并用其发送 AJAX 请求,然后将返回的内容打印在控制台中。

关于原生 AJAX 的详细说明,可以阅读这里。

点击按钮,可以看到浏览器发送了一个类型为 XHR(XMLHttpRequest) 的请求到服务端:

image-20230913114146316

并且可以看到控制台输出。

2.案例:验证用户是否存在

服务端:

@WebServlet("/user/exist")
public class ExistController extends HttpServlet {private UserService userService = new UserServiceImpl();@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String username = req.getParameter("username");boolean exists = userService.checkUsernameExists(username);if (exists){resp.getWriter().print("true");}else{resp.getWriter().print("false");}}
}

在页面表单中输入用户名的元素上设置光标焦点事件:

<input name="username" type="text" id="username" onblur="checkUsernameExists()">

对应的 js:

// 检查用户名是否存在
function checkUsernameExists() {let username = $("input#username").val();const xhttp = new XMLHttpRequest();xhttp.onreadystatechange = function() {if (this.readyState == 4 && this.status == 200) {let result = this.responseText;console.log(result)if (result == "true"){console.log("用户名已存在")$("span#username_err").html("用户名已存在");$("span#username_err").show();}else{$("span#username_err").hide();}}};xhttp.open("POST", "http://localhost:8080/login-demo/user/exist?username="+username, true);xhttp.send();
}

3.Axios

Axios 是封装好的一个异步调用框架,可以运行于浏览器或 Node.js 服务器上。

使用 Axios 可以让我们之前的 AJAX 调用的代码更为简单。

在 html 中添加对 Axios 的引用:

<head><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>

修改 AJAX 部分代码,使用 Axios 进行调用:

// 检查用户名是否存在
function checkUsernameExists() {let username = $("input#username").val();axios({method: 'post',url: '/login-demo/user/exist?username=' + username}).then(function (response) {let result = response.data;if (result) {$("span#username_err").html("用户名已存在");$("span#username_err").show();} else {$("span#username_err").hide();}});
}

axios对象可以接收一个 js 对象,其method属性指定了 HTTP Method,url指定请求的 url。

需要注意的是,这里 Axios 将返回的响应报文体进行了解析,所以这里response.data不是一个字符串形式的truefalse,而是 bool 类型。

除了上边的方式,还可以使用一种简化的方式:

// 检查用户名是否存在
function checkUsernameExists() {let username = $("input#username").val();axios.post('/login-demo/user/exist?username=' + username).then(function (response) {let result = response.data;if (result) {$("span#username_err").html("用户名已存在");$("span#username_err").show();} else {$("span#username_err").hide();}});
}

4.JSON

通常浏览器和服务端通过异步调用方式传输的数据结构都很复杂,所以会使用 JSON 格式的字符串进行传输。

浏览器端:

// 检查用户名是否存在
function checkUsernameExists() {let username = $("input#username").val();axios.post('/login-demo/user/exist', {"username": username}).then(function (response) {let result = response.data;if (result.exist) {$("span#username_err").html("用户名已存在");$("span#username_err").show();} else {$("span#username_err").hide();}});
}

服务端:

@WebServlet("/user/exist")
public class ExistController extends HttpServlet {private UserService userService = new UserServiceImpl();@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {BufferedReader reader = req.getReader();StringBuilder sb = new StringBuilder();do{String line = reader.readLine();if (line == null){break;}sb.append(line);}while (true);String content = sb.toString();System.out.println(content);JSONObject jsonObject = JSON.parseObject(content);String username = (String) jsonObject.get("username");boolean exists = userService.checkUsernameExists(username);JSONObject resultJO = new JSONObject();if (exists){resultJO.put("exist", true);}else{resultJO.put("exist", false);}resp.setContentType("application/json;charset=UTF-8");resp.getWriter().print(resultJO.toJSONString());}
}

这里使用了一个中间件 FastJSON,用于在服务端解析和编码 JSON 字符串:

<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.75</version>
</dependency>

5.案例:异步加载品牌列表

可以用 Axios+JSON 异步加载品牌列表。

后端:

@WebServlet("/brand/list")
public class ListController extends HttpServlet {// .../*** 获取品牌列表* @param request* @param response* @throws ServletException* @throws IOException*/@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/json;charset=utf-8");List<Brand> brands = brandService.getAllBrands();response.getWriter().print(JSON.toJSONString(brands));}
}

前端:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript" src="/login-demo/js/jquery-3.7.1.min.js"></script><script type="text/javascript" src="/login-demo/js/axios-0.18.0.js"></script>
</head>
<body>
<h1>${username},欢迎您</h1>
<a href="/login-demo/brand/add"><input type="button" value="新增"></a><br>
<hr>
<table id="brandsTable" border="1" cellspacing="0" width="800"><tr><th>序号</th><th>品牌名称</th><th>企业名称</th><th>排序</th><th>品牌介绍</th><th>状态</th><th>操作</th></tr><tr align="center" class="brandsRow" hidden="hidden"><td></td><td></td><td></td><td></td><td></td><td></td><td><a href="/login-demo/brand/edit?id=#" class="edit">修改</a><a href="/login-demo/brand/delete?id=#" class="delete">删除</a></td></tr>
</table>
</body>
<script type="text/javascript">$(document).ready(function () {loadBrandsTable();});function loadBrandsTable() {let table = $("table#brandsTable");let demoRow = table.find("tr.brandsRow:first");// 获取品牌列表信息axios({"method": "POST","url": "/login-demo/brand/list"}).then((resp)=>{let brands = resp.data;brands.map((brand)=>{let newRow = demoRow.clone();console.log(newRow);fillRowData(newRow, brand);table.find("tr:last").after(newRow);});});}function fillRowData(newRow, data){newRow.children("td:eq(0)").html(data.id);newRow.children("td:eq(1)").html(data.brandName);newRow.children("td:eq(2)").html(data.companyName);newRow.children("td:eq(3)").html(data.ordered);newRow.children("td:eq(4)").html(data.description);let status = "禁用";if (data.status == 0){status = "启用";}newRow.children("td:eq(5)").html(status);newRow.children("td:eq(6)").children("a.edit").attr("href","/login-demo/brand/edit?id="+data.id);newRow.children("td:eq(6)").children("a.delete").attr("href","/login-demo/brand/delete?id="+data.id);newRow.removeAttr("hidden");}
</script>
</html>

这里为表格添加了一个用于示例数据的行,并使用 JQuery 选择器获取这个行的 DOM 对象,并进行拷贝,填充数据后依次添加到表格的末尾。

用类似的方式可以将新增品牌也修改为前端异步提交而非表单提交,这里不再赘述。

6.Template

在前边的示例中,使用一个表单中的“隐藏行”作为模板,用于遍历品牌信息并填充数据,然后添加到表格 DOM 树中,并最终称为一个有数据的表格。

这样做是可行的,但是“隐藏行”只是用户看不见,实际上依然是存在的,并且会影响页面的渲染速度。对此,有一个专门用于此类问题的 Html 标签 template,可以用它作为模板 Html 代码存放的位置。这样做的好处在于,<template>标签中的内容是一个 DocumentFragment(文档片段),它不是当前Document(文档)的一部分,不是任何DOM对象的子节点,所以它不会参与页面渲染,就不影响性能。但同时我们依然可以通过 js 代码获取其内部 DOM 结构,作为模板进行使用。

使用 template 标签改写之前的示例:

<table id="brandsTable" border="1" cellspacing="0" width="800"><tr><th>序号</th><th>品牌名称</th><th>企业名称</th><th>排序</th><th>品牌介绍</th><th>状态</th><th>操作</th></tr>
</table>
<template id="rowTemplate"><tr align="center"><td></td><td></td><td></td><td></td><td></td><td></td><td><a href="/login-demo/brand/edit?id=#" class="edit">修改</a><a href="/login-demo/brand/delete?id=#" class="delete">删除</a></td></tr>
</template>

对应的 js 代码:

function loadBrandsTable() {let table = $("table#brandsTable");let demoRow = $("#rowTemplate").get(0).content.querySelector("tr");// 获取品牌列表信息axios({"method": "POST","url": "/login-demo/brand/list"}).then((resp)=>{let brands = resp.data;brands.map((brand)=>{let newRow = $(demoRow).clone();// console.log(newRow);fillRowData(newRow, brand);table.find("tr:last").after(newRow);});});
}

需要注意的是,template 标签的内容是文档片段,而文档片段并不是当前文档的一部分。如果用开发者工具观察文档结构:

image-20230915104618250

template 标签本身是当前文档的一部分,是可以通过文档操作的方式获取的,比如用 JQuery:$("#rowTemplate").get(0)。但是,其内部的内容是一个文档片段(#document-fragment标记的部分),这部分内容并不属于当前文档,所以你是没办法用类似$("#rowTemplate").children()的方式获取到的,这个筛选项的长度只能是0,没有任何内容。

除了上边示例中使用templatecontent属性获取 DOM 对象外,还可以用 JQuery 的方式:

let demoRow = $($("#rowTemplate").html()).get(0);

这里是先获取template标签内的 html 内容,然后用 JQuery 解析以生成 DOM 对象。

两者效果是相同的,只是写法不同。

本文的完整示例可以从这里获取。

7.参考资料

  • 黑马程序员JavaWeb基础教程
  • AJAX 简介 (w3school.com.cn)
  • jQuery 教程 (w3school.com.cn)
  • DocumentFragment - Web API 接口参考 | MDN (mozilla.org)
  • DOMParser - Web API 接口参考 | MDN (mozilla.org)
  • javascript中html字符串转化为jquery dom对象的方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/86217.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32-无人机-电机-定时器基础知识与PWM输出原理

电机控制基础——定时器基础知识与PWM输出原理 - 掘金单片机开发中&#xff0c;电机的控制与定时器有着密不可分的关系&#xff0c;无论是直流电机&#xff0c;步进电机还是舵机&#xff0c;都会用到定时器&#xff0c;比如最常用的有刷直流电机&#xff0c;会使用定时器产生PW…

Linux学习记录——삼십 socket编程---udp套接字

文章目录 UDP套接字简单通信1、服务端1、创建文件&#xff0c;写框架2、用命令行参数调起程序3、服务端运行逻辑 2、客户端1、创建套接字2、发送数据 3、测试4、通信5、加功能1、处理数据2、群聊 6、Windows下socket编程的不同 UDP套接字简单通信 1、服务端 1、创建文件&…

vue+element plus 使用table组件,清空用户的选择项

<el-table ref"tableRef"> .... </el-table> <script lang"ts" setup> import { onMounted, reactive, ref, nextTick } from vue const clearBtn () > {console.log(清空用户的选择项)tableRef.value.clearSelection() } </scr…

基于Java的酒店管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

docker alpine:3.16 root权限安装Anaconda3-2020.07-Linux-x86_64和jdk

首先查看系统版本: rootfv-az454-287:/tmp# uname -a Linux fv-az454-287 5.15.0-1046-azure #53~20.04.1-Ubuntu SMP Mon Aug 28 14:17:23 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux rootfv-az454-287:/tmp# grep NA /etc/os-release NAME"Ubuntu" PRETTY_NAME&q…

在c#中使用CancellationToken取消任务

目录 &#x1f680;介绍&#xff1a; &#x1f424;简单举例 &#x1f680;IsCancellationRequested &#x1f680;ThrowIfCancellationRequested &#x1f424;在控制器中使用 &#x1f680;通过异步方法的参数使用cancellationToken &#x1f680;api结合ThrowIfCancel…

Docker Compose初使用

简介 Docker-Compose项目是Docker官方的开源项目&#xff0c;负责实现对Docker容器集群的快速编排。 Docker-Compose将所管理的容器分为三层&#xff0c;分别是 工程&#xff08;project&#xff09;&#xff0c;服务&#xff08;service&#xff09;以及容器&#xff08;cont…

【论文阅读 09】融合门控自注意力机制的生成对抗网络视频异常检测

2021年 中国图象图形学报 摘 要 背景&#xff1a; 视频异常行为检测是智能监控技术的研究重点&#xff0c;广泛应用于社会安防领域。当前的挑战之一是如何提高异常检测的准确性&#xff0c;这需要有效地建模视频数据的空间维度和时间维度信息。生成对抗网络&#xff08;GANs&…

Stable Diffusion 系统教程 | 强大的ControlNet 控制网

2023年的2月13日&#xff0c;一款名叫ControlNet的插件横空出世&#xff0c;AI绘画变得更加可控 ControlNet直译过来很简单&#xff0c;就叫做控制网&#xff0c;开发者是一名华裔&#xff0c;毕业于苏州大学&#xff0c;目前在斯坦福做读博士一年级&#xff0c;大佬大佬&…

【lesson10】fork创建进程的现象解答

文章目录 fork现象fork问题 fork现象 我们先来看一段代码。 大家觉得这段代码的printf会打印几次&#xff1f; 结果&#xff1a; 我们可以清楚的看到&#xff0c;第二个printf打印了2次。 我们再来看一段不可思议的代码&#xff1a; 运行结果&#xff1a; 我们可以看到这r…

批量、在线学习, 参数、非参数学习

批量学习&#xff08;Batch Learning&#xff09;和在线学习&#xff08;Online Learning&#xff09; 批量学习 批量学习的概念非常容易理解&#xff0c;我们之前介绍的许多机器学习算法&#xff0c;如果没有特殊说明&#xff0c;都可以采用批量学习的方式。批量学习的过程通…

iOS应用中的内存泄漏问题解决

解决iOS应用中的内存泄漏问题是非常重要的&#xff0c;因为内存泄漏可能导致应用变得缓慢或不稳定。以下是一些解决iOS内存泄漏问题的工具和方法&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 工具&…

SQLAlchemy Oracle Database 23c Free 集成之旅

SQLAlchemy & Oracle Database 23c Free 集成之旅 1. SQLAlchemy 是什么2. Oracle Database 23c Free 是什么3. 运行 Oracle Database 23c Free4. 学习 SQLAlchemy 统一教程4-1. 安装依赖库4-2. 建立连接 - 引擎4-3. 使用事务和 DBAPI4-3-1. 获取连接4-3-2. 提交更改4-3-3.…

【PowerQuery】Python自动刷新本地数据

Python数据刷新是开发爱好者和开发人员开发的PowerBI刷新模块进行数据刷新的手段,Python进行数据刷新是通过刷新PowerBI Desktop 的模式进行数据刷新。目前常用的Python的数据刷新模块是PbixRefresher,图为相关的模块和版本。 由于当前的脚本基于英文版本的PowerBI Desktop进…

【100天精通Python】Day69:Python可视化_实战:导航定位中预测轨迹和实际轨迹的3D动画,示例+代码

目录 1. 预测的3D轨迹和实际轨迹的动画图&#xff0c;同时动态更新 2 真值轨迹设置为静态的&#xff0c;预测轨迹不断更新 3 网格的三维坐标系有旋转运动&#xff0c;以此全方位展示预测轨迹和真值轨迹之间的空间关系 1. 预测的3D轨迹和实际轨迹的动画图&#xff0c;同时动态更…

vivo面试-Java

一、JAVA八股 1、Java实现线程的三种方式 (1) 继承 Thread 类&#xff1a; 创建一个新类&#xff0c;该类继承自Thread类&#xff0c;并重写run方法。然后创建该类的实例&#xff0c;并调用它的start方法来启动线程。 public class MyThread extends Thread {public void r…

【owt】 Intel® Media SDK for Windows: MSDK2021R1

https://www.intel.com/content/www/us/en/developer/articles/tool/media-sdk.html官方网不提供下载了: 2021地址 直接下载: MSDK2021R1.exe老版本 Intel Media SDK(Windows版本) 大神的介绍:owt-client-native 需要 https://github.com/open-webrtc-toolkit/owt-client…

罗德里格斯公式

1.点乘 A ⃗ ⋅ B ⃗ ∣ A ⃗ ∣ ∣ B ⃗ ∣ c o s ⟨ A ⃗ , B ⃗ ⟩ \vec{A} \cdot \vec{B} \left | \vec{A} \right | \left | \vec{B} \right | cos\left \langle \vec{A}, \vec{B} \right \rangle A ⋅B ​A ​ ​B ​cos⟨A ,B ⟩ 对应几何意义&#xff1a;向量 A ⃗…

面向使用者的git与gerrit相关笔记

git与gerrit相关笔记 前言一、gerrit是什么&#xff1f;二、一些配置1.先配置全局email 和name2.gerrit配置ssh key3.可能遇到的问题 三、提交代码和合并冲突常用Git命令三件套严格的要求 总结 前言 本文是介绍什么是gerrit和工作中git与gerrit相关的命令来避免一些提交代码的…