目录
一. 异步请求举例
二. Ajax 异步请求详解
2.1 Ajax 简介
2.2 XMLHttpResponse对象的属性和方法
2.3 ajax() 的使用方式
三. Ajax 请求代码举例
3.1 确认用户名是否被占用例子
3.1.1 用户注册界面展示
3.1.2 前端用户注册表单代码
3.1.3 前端 JavaScript 发送 Ajax 请求的代码
3.1.4 后端代码
3.2 修改用户信息举例
3.2.1 浏览器页面效果展示
3.2.2 用户表单代码
3.2.3 前端 JavaScript 代码
3.2.4 后端 Controller 层接口代码
3.2.5 业务层代码代码
3.2.6 DAO层代码,Mapper层代码
3.3 代码仓库及相关视频
四. Ajax的优缺点
一. 异步请求举例
例子一:
比如用户注册完毕之后点击了提交按钮提交表单,浏览器会发送HTTP请求将用户填写的数据提交到后端服务器;而用户在注册的时候,填写用户名时,输入一个用户名,有时候会显示该用户名已被占用,请选择另外一个,那么它是怎么知道这个用户名已经存在的了呢?
其实就是通过异步请求来完成的,当用户输入完毕用户名之后,它会在不影响用户使用的情况下不用刷新网页向服务器发送异步HTTP请求,向数据库表中查询当前用户名是否已经存在。
如果返回值为NULL,则说明该用户名尚未被占用;
如果返回值不为NULL,则说明该用户名已被其他用户占用,不能使用此用户名;
例子二:
比喻电商网站,我们会发现,页面上的数据都是在不断变化的,热销商品在不断变化,那么它是如何做到的呢?
其实也可以通过异步请求来完成,用户在浏览商品的时候,页面的后台在不断的向服务器发送HTTP请求,查询数据库中最新的商品数据,返回给前端,前端浏览器解析返回的数据在展示给用户。
二. Ajax 异步请求详解
2.1 Ajax 简介
现在来看,Ajax 并不是一个很新的技术,但是它的异步请求思想还是直接我们去借鉴和思考的。现在的很多前端框架,归根结底还是封装的 JavaScript 代码,Ajax 也不例外。实质上,Ajax 只是 JQuery 框架封装的一个函数,也可以称之为 "$.ajax()" 函数,通过调用 ajax() 函数加载发送异步请求,JavaScript 提供了一个对象XHR(XMLHttpResponse),它就是 Ajax 的核心对象,发送请求以及接收服务器数据的返回全靠它。
此外,现代浏览器全都内置了 XMLHttpResponse 对象,所以都支持的 XMLHttpResponse 对象数据。
说白了就一句话:Ajax 是一种异步无刷新发送网络请求的技术。
2.2 XMLHttpResponse对象的属性和方法
(1)XMLHttpResponse 属性
属性 | 描述 |
status | 返回请求的状态号200:"OK" 403:"Forbidden" 404:"Not Found" |
statusText | 返回状态文本(比如"OK"或"Not Found") |
responseText | 以字符串返回响应数据 |
responseXML | 以 XML 数据返回响应数据 |
readyState | 保存 XMLHttpResponse 的状态。 0:请求未初始化; 1:服务器连接已建立; 2:请求已收到; 3:正在处理请求; 4:请求已完成且响应已就绪; |
onreadystatechange | 定义当 readyState 属性变化发生变化时被调用的函数 |
(2)XMLHttpResponse 方法
方法 | 描述 |
send() | 向服务器发送GET请求 |
send(String) | 向服务器发送POST请求 |
open(method,url,async,users,psw) | method:规定请求的方法; url:请求路径GET和POST; user:可选的用户名称; psw:可选的密码; |
sendRequestHeader() | 向要发送的报头添加标签/值对 |
abort() | 取消当前请求 |
getAllResponseHeaders() | 返回头部信息 |
getResponseHeader() | 返回特定的头部信息 |
2.3 ajax() 的使用方式
ajax() 函数的使用方式就是直接写 "$.ajax(参数...)",参数需要传递一个方法体;
众所周知,JavaScript 方法体如下代码所示
function(){函数体...
}
所以 ajax() 函数的语法如下
$.ajax(function(){函数体...
})
但是,ajax 需要我们传入的是一个方法方法体,也就是大括号和大括号内不的内容,即"{函数体...}"。
因此,我们实际使用的时候通常会将 function() 省略不写,就变成了下面这种格式
$.ajax({函数体...
})
此外,函数体包含以下几个参数,参数与参数之间使用","逗号进行分割,每一组参数之间使用":"冒号进行分割;并且称它们的顺序没有要求,谁写在最上面都可以。如下是一种常用的书写方式,
$.ajax({url:"",type:"",async:"",data:"",dataType:"",contentType:"",success:function(result){//result:服务器响应的数据//处理服务器响应的数据},error:function(){//处理请求失败的情况}
})
各个参数的含义如下表格所示
参数 | 功能描述 |
url | 表示请求的地址(url地址),不能包含参数列表的内容。 url举例:http://localhost:8080/users/reg |
type | 请求类型(常用请求类型为GET和POST)。 type举例 type:"POST" |
async | 是否同步刷新数据,默认为 ture 开启状态 |
data | 向指定的URL地址提交的数据。 举例如 data:"username=tom&password=123" |
dataType | 提交的数据类型,一般都是指定为JSON格式 举例如 dataType:"json" |
contentType | 设置请求头 |
success | 服务器正常响应客户端时,会自动调用success参数的方法,将服务器返回的数据以参数的形式传递给这个方法的参数上 |
error | 当服务器为正常响应客户端时,会自动调用error参数的方法,将服务器返回的数据以参数的形式传递给这个方法的参数上 |
三. Ajax 请求代码举例
3.1 确认用户名是否被占用例子
3.1.1 用户注册界面展示
我们都知道,很多系统中,用户昵称都是唯一的,特别是在游戏中,所以我们做一个用户昵称确认的方法,当用户输入玩用户名称之后,校验用户名是否已被占用,
当我们启动项目后,在用户注册界面,用户只要在文本框内输入用户名注册,再点击其它地方,就会触发失焦事件,发送HTTP请求到后端去查询用户希望注册的用户名是否已经存在,效果如下图所示;
当然了,在实际公司开发的项目中,通常不会采用弹窗的方式提示用户,而是在用户名一行下面显示红色字体进行提示;我们这里就不做那么麻烦了,主要是为了让同学们知道这种需求的思路设计。
3.1.2 前端用户注册表单代码
<form id="form-reg" class="form-horizontal" role="form">
<!--用户名-->
<div class="form-group"><label class="col-md-3 control-label">名字:</label><div class="col-md-8"><input id="username" name="username" type="text" class="form-control" placeholder="请输入用户名"></div>
</div>
<!--密码-->
<div class="form-group"><label class="col-md-3 control-label"> 密码:</label><div class="col-md-8"><input id="password" name="password" type="text" class="form-control" placeholder="请输入密码"></div>
</div>
<!--确认密码-->
<div class="form-group"><label class="col-md-3 control-label"> 确认密码:</label><div class="col-md-8"><input type="text" class="form-control" placeholder="请再次输入密码"></div>
</div>
<!--提交按钮-->
<div class="form-group"><label class="col-md-3 control-label"></label><div class="col-md-8"><input id="btn-reg" class="btn btn-primary" type="button" value="立即注册" /><span class="pull-right"><small>已经有账号?</small><a href="login.html">登录</a></span></div>
</div>
</form>
3.1.3 前端 JavaScript 发送 Ajax 请求的代码
// 用户输入用户名,发送ajax请求确认是否已经存在,$("#username").blur(function () {$.ajax({url: "/users/getByUsername",type: "get",dataType: "json",data: {username: $("#username").val(),}, // 正确的格式success:function (json) {if(json.code == 200 && json.data != null){// 提示用户该用户名已被占用alert("该用户名已被占用")}else{// 不做任何提示alert("该用户名未被占用")}},error:function (xhr) {alert("查询用户名时产生未知的异常" + xhr.status+xhr.message);},});});
3.1.4 后端代码
// Controller 层接口代码@RequestMapping(value = "/getByUsername",method = GET)public JsonResult<User> getByUsername(String username){User data = userService.findByUsername(username);return new JsonResult<>(OK ,data);}// Service 层业务类代码public User findByUsername(String username) {return userMapper.findByUsername(username);}// Dao 层数据访问层代码User findByUsername(@Param("username") String username);// Mapper 层SQL语句编写<select id="findByUsername" resultType="com.cy.store.entity.User">select * from t_user where username = #{username}</select>
3.2 修改用户信息举例
3.2.1 浏览器页面效果展示
我们只关注中间用户信息的模块,用户登陆成功之后,点击进入修改信息界面,就会马上发送 Ajax 请求查询用户信息返回到前端,前端再进行展示;
当用户修改完成信息之后,点击修改按钮,会再次发送 Ajax 请求,将新的用户数据传递给后端服务器,然后修改书库结果,然后前端同步刷新用户数据,根本不需要刷新浏览器页面,非常快捷方便。
3.2.2 用户表单代码
设置表单 id="form-change-info";修改按钮 id="btn-change-info";
<!--修改资料表单开始-->
<form id="form-change-info" class="form-horizontal" role="form"><div class="form-group"><label class="col-md-2 control-label">用户名:</label><div class="col-md-8"><input class="form-control" id="username" name="username" type="text"></div></div><div class="form-group"><label class="col-md-2 control-label">电话号码:</label><div class="col-md-8"><input class="form-control" id="phone" name="phone" type="text"></div></div><div class="form-group"><label class="col-md-2 control-label">电子邮箱:</label><div class="col-md-8"><input class="form-control" id="email" name="email" type="text"></div></div><div class="form-group"><label class="col-md-2 control-label">性别:</label><div class="col-md-8"><label class="radio-inline"><input id="gender-male" type="radio" name="gender" value="1">男</label><label class="radio-inline"><input id="gender-female" type="radio" name="gender" value="0">女</label></div></div><div class="form-group"><div class="col-sm-offset-2 col-sm-10"><input id="btn-change-info" type="button" class="btn btn-primary" value="修改" /></div></div>
</form>
3.2.3 前端 JavaScript 代码
既然用户修改信息,进入用户信息页面,必然会有旧的信息。所以我们需要先定义一个定义一个初始填充数据的请求,正如下带代码所示,然后再获取需该按钮并为其绑定单击事件,单击之后发送 ajax 请求到后端修改数据
<script>// 进入修改信息页面,发送ajax请求先查询出已有的用户信息渲染到页面$(document).ready(function () {$.ajax({url: "/users/getByUid",type: "GET",dataType: "json",success: function(json) {if (json.code == 200) {$("#username").val(json.data.username);$("#email").val(json.data.email);$("#phone").val(json.data.phone);let radio = json.data.gender == 0 ? $("#gender-female"): $("#gender-male");radio.prop("checked", true);} else {alert("修改失败");}},error: function(xhr) {alert("修改失败"+ xhr.message);}});});// 用户点击修改按钮,发送ajax请求修改用户信息$("#btn-change-info").click(function (){$.ajax({url: "/users/changeInfo",type: "POST",dataType: "json",data: $("#form-change-info").serialize(),success: function(json) {if (json.code == 200) {alert("修改成功");location.href = "userdata.html";}else{alert("修改失败");}},error: function(xhr) {alert("修改失败"+ xhr.message);},});});
</script>
3.2.4 后端 Controller 层接口代码
上述 Ajax 请求正是由后端的接口进行接收并处理;
/* 获取用户信息 */@RequestMapping(value = "/getByUid",method = GET)public JsonResult<User> getUserByUid(HttpSession session){Integer uid = getUidFromSession(session);User data = userService.findByUid(uid);return new JsonResult<>(OK ,data);}/* 用户修改个人资料 */@RequestMapping(value = "/changeInfo", method = POST)public JsonResult<Void> changeInfo(User user,HttpSession session){// user对象中要四个数据,username,phone,email,genderInteger uid = getUidFromSession(session);String username = getUsernameFromSession(session);userService.changeInfo(uid,username,user);return new JsonResult<>(OK);}
3.2.5 业务层代码代码
@Overridepublic User findByUid(Integer id) {User result = userMapper.findByUid(id);if (result == null || result.getIsDelete() == 1){throw new UserNotFoundException("该用户不存在");}User user = new User();user.setUsername(result.getUsername());user.setPhone(result.getPhone());user.setEmail(result.getEmail());user.setGender(result.getGender());return user;}@Overridepublic void changeInfo(Integer id, String username, User user) {User result = userMapper.findByUid(id);if (result == null || result.getIsDelete() == 1){throw new UserNotFoundException("该用户不存在");}user.setUid(id);user.setModifiedUser(username);user.setModifiedTime(new Date());Integer rows = userMapper.updateInfoByUid(user);if (rows != 1){throw new UpdateException("更新时发生错误");}}
3.2.6 DAO层代码,Mapper层代码
User findByUid(@Param("uid") Integer uid);<select id="findByUid" resultType="com.cy.store.entity.User">select * from t_user where uid = #{uid}</select>Integer updateInfoByUid(User user);<update id="updateInfoByUid">update t_user set<!--if表示条件判断标签,test接收的是返回值为布尔类型的条件,如果test结果为true,则执行if标签内的语句--><if test="phone!=null">phone = #{phone},</if><if test="email!=null">email = #{email},</if><if test="gender!=null">gender = #{gender},</if>modified_user = #{modifiedUser},modified_time = #{modifiedTime}where uid = #{uid}</update>
3.3 代码仓库及相关视频
小编这里举的代码例子也是从B站上学习的,相关视频链接
【SpringBoot项目实战完整版】SpringBoot+MyBatis+MySQL电脑商城项目实战_哔哩哔哩_bilibili【SpringBoot项目实战完整版】SpringBoot+MyBatis+MySQL电脑商城项目实战共计41条视频,包括:01-项目环境搭建、02-用户注册-持久层、03-用户注册-业务层等,UP主更多精彩视频,请关注UP账号。https://www.bilibili.com/video/BV1bf4y1V7Bx/?spm_id_from=333.788.videopod.episodes&vd_source项目的中代码我已经存储到了自己的 Gitee 仓库中,仓库已经公开,小伙伴们可以自己拉取,具体操作可以看项目MD文档,适合SSM和SpringBoot小白同学做的一个前端项目。
项目目前代码仍在持续更新过程中,小编也会把自己学习和编写的代码推到仓库中,小编主要也是为了学习 Ajax 发送请求到后端与后端交互这一知识点,所以主要推送前端代码,效果伙伴们也可以自己看视频自己敲一遍哦。
store: 电脑商城项目源码,包含前后端。https://gitee.com/haust_zhang/store
四. Ajax的优缺点
Ajax 的优点:
(1)可以无需刷新页面与服务器进行通信;
(2)允许根据用户事件来更新部分页面内容;
Ajax 的缺点:
(1)没有浏览历史,不能回退;
(2)存在跨域问题(同源),有解决办法,下文会讲到;
(3)SEO不友好;