1. 概述
1.1 官方文档
Ajax 在线文档:
https://www.w3school.com.cn/js/js_ajax_intro.asp
1.2 Ajax 基本介绍
1.2.1 Ajax 是什么
- AJAX 即”Asynchronous Javascript And XML”(异步 JavaScript 和 XML)
-
Ajax 是一种浏览器
异步发起请求(指定发哪些数据),局部更新页面
的技术 -
传统的方式
1.2.2 Ajax 经典应用场景
- 搜索引擎根据用户输入关键字,自动提示检索关键字
- 动态加载数据,按需取得数据【树形菜单、联动菜单…】
- 改善用户体验。【输入内容前提示、带进度条文件上传…】
- 电子商务应用。 【购物车、邮件订阅…】
- 访问第三方服务。【访问搜索服务、rss 阅读器】
-
页面局部刷新, https://piaofang.maoyan.com/dashboard
1.3 Ajax 原理示意图
1.3.1 传统的 WEB 应用
1.3.2 Ajax 原理示意图
2. JavaScript 原生 Ajax 请求
2.1 Ajax 文档
在线文档:
https://www.w3school.com.cn/js/js_ajax_intro.asp
2.2 应用实例
验证用户名是否存在
演示 javascript 发送原生 ajax 请求的案例
- 在输入框输入用户名
- 点击验证用户名, 使用 ajax 方式, 服务端验证该用户名是否已经占用了, 如果该用户已经占用, 以 json 格式返回该用户信息
- 假定用户名为 king , 就不可用, 其它用户名可以=》 后面我们接入 DB[Mysql+JDBC]
- 对页面进行局部刷新, 显示返回信息
- 小思考: 为什么直接返回用户名是否可用信息, 完成案例后, 再思考?
简单的思路分析.=> 程序框架图(老师画出框架图)-> 先思路-> 走代码 [希望小伙伴知道,老师是怎么思考]
代码:
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户注册</title>
<script type="text/javascript">
window.onload = function () { //页面加载后执行function
var checkButton = document.getElementById("checkButton");
//给checkButton绑定onclick
checkButton.onclick = function () {
//1. 创建XMLHttpRequest对象(!!!) [ajax引擎对象]
var xhr = new XMLHttpRequest();
// 获取用户填写的用户名
var uname = document.getElementById("uname").value;
//2. 准备发送指定数据 open, send
//老师解读
//(1)"GET" 请求方式可以 GET/POST
//(2)"/ajax/checkUserServlet?username=" + uname 就是 url
//(3)true , 表示异步发送
xhr.open("GET", "/ajax/checkUserServlet?uname=" + uname, true);
//老师说明,在send函数调用前,给XMLHttpRequest 绑定一个事件onreadystatechange
//该事件表示,可以去指定一个函数,当数据变化,会触发onreadystatechange
// 每当 xhr对象readyState 改变时,就会触发 onreadystatechange 事件
xhr.onreadystatechange = function () {
//如果请求已完成,且响应已就绪, 并且状态码是200
if (xhr.readyState == 4 && xhr.status == 200) {
//把返回的jon数据,显示在div
document.getElementById("div1").innerHTML = xhr.responseText;
//console.log("xhr=", xhr)
var responseText = xhr.responseText;
//console.log("返回的信息=" + responseText);
if (responseText != "") {
document.getElementById("myres").value = "用户名不可用"
} else {
document.getElementById("myres").value = "用户名可用"
}
}
}
//3. 真正的发送ajax请求[http请求]
// 老师再说明如果你POST 请求,再send("发送的数据")
xhr.send();
}
}
</script>
</head>
<body>
<h1>用户注册~</h1>
<form action="/ajax/checkUserServlet" method="post">
用户名字:<input type="text" name="username" id="uname">
<input type="button" id="checkButton" value="验证用户名">
<input style="border-width: 0;color: red" type="text" id="myres"><br/><br/>
用户密码:<input type="password" name="password"><br/><br/>
电子邮件:<input type="text" name="email"><br/><br/>
<input type="submit" value="用户注册">
</form>
<h1>返回的json数据</h1>
<div id="div1"></div>
</body>
</html>
User.java
/**
* User类就是一个javabean/pojo/entity/domain
*/
public class User {
private Integer id;
private String username;
private String pwd;
private String email;
//必须提供一个无参构造器, 是给我们的反射使用
public User() {
}
public User(Integer id, String username, String pwd, String email) {
this.id = id;
this.username = username;
this.pwd = pwd;
this.email = email;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
CheckUserServlet.java
public class CheckUserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//System.out.println("CheckUserServlet 被调用....");
//接收ajax提交的数据
String uname = request.getParameter("uname");
System.out.println("uname= " + uname);
response.setContentType("text/html;charset=utf-8");
假定用户名为 king , 就不可用, 其它用户名可以
if("king".equals(uname)) {//不能使用king用户名
//后面这个信息,是从DB获取
User king = new User(100, "king", "666", "king@sohu.com");
//把 king 转成 json字符串
String strKing = new Gson().toJson(king);
//返回
response.getWriter().write(strKing);
} else {
//如果用户名可以用,返回""
response.getWriter().write("");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
完成测试, 注意看 FF 抓包
2.3 课后作业
2.3.1 作业布置
● 需求分析: 到数据库去验证用户名是否可用
- 点击验证用户名, 到数据库中验证用户名是否可用
- 创建数据库 ajaxdb , 创建表 user 表 自己设计(自己试试)
- 使用 ajax 方式, 服务端验证该用户名是否已经占用了, 如果该用户已经占用, 以 json格式返回该用户信息
- 对页面进行局部刷新, 显示返回信息
- 只需要在前面的应用实例中,进行升级, 接入 DB
-
提示: java 基础[Mysql+JDBC+数据库连接池 => 满汉楼项目]
● 思路分析(程序框架图)
2.3.2 实现
项目环境准备:
导入相关jar包!!
构建项目:
数据库准备:
CREATE DATABASE ajaxdb
USE ajaxdb
-- 创建表
CREATE TABLE `user` (
id INT PRIMARY KEY,
username VARCHAR(32) NOT NULL DEFAULT '',
pwd CHAR(32) NOT NULL DEFAULT '',
email VARCHAR(32) NOT NULL DEFAULT '')CHARSET utf8 ENGINE INNODB
-- 测试数据
INSERT INTO `user` VALUES(100, 'king', MD5('123'), 'king@qq.com');
INSERT INTO `user` VALUES(200, 'hspedu', MD5('666'), 'hspedu@qq.com');
SELECT * FROM `user`
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户注册</title>
<script type="text/javascript">
window.onload = function () { //页面加载后执行function
var checkButton = document.getElementById("checkButton");
//给checkButton绑定onclick
checkButton.onclick = function () {
//1. 创建XMLHttpRequest对象(!!!) [ajax引擎对象]
var xhr = new XMLHttpRequest();
// 获取用户填写的用户名
var uname = document.getElementById("uname").value;
//2. 准备发送指定数据 open, send
//老师解读
//(1)"GET" 请求方式可以 GET/POST
//(2)"/ajax/checkUserServlet?username=" + uname 就是 url
//(3)true , 表示异步发送
xhr.open("GET", "/ajax/checkUserServlet?uname=" + uname, true);
//老师说明,在send函数调用前,给XMLHttpRequest 绑定一个事件onreadystatechange
//该事件表示,可以去指定一个函数,当数据变化,会触发onreadystatechange
// 每当 xhr对象readyState 改变时,就会触发 onreadystatechange 事件
xhr.onreadystatechange = function () {
//如果请求已完成,且响应已就绪, 并且状态码是200
if (xhr.readyState == 4 && xhr.status == 200) {
//把返回的jon数据,显示在div
document.getElementById("div1").innerHTML = xhr.responseText;
//console.log("xhr=", xhr)
var responseText = xhr.responseText;
//console.log("返回的信息=" + responseText);
if (responseText != "") {
document.getElementById("myres").value = "用户名不可用"
} else {
document.getElementById("myres").value = "用户名可用"
}
}
}
//3. 真正的发送ajax请求[http请求]
// 老师再说明如果你POST 请求,再send("发送的数据")
xhr.send();
}
}
</script>
</head>
<body>
<h1>用户注册~</h1>
<form action="/ajax/checkUserServlet" method="post">
用户名字:<input type="text" name="username" id="uname">
<input type="button" id="checkButton" value="验证用户名">
<input style="border-width: 0;color: red" type="text" id="myres"><br/><br/>
用户密码:<input type="password" name="password"><br/><br/>
电子邮件:<input type="text" name="email"><br/><br/>
<input type="submit" value="用户注册">
</form>
<h1>返回的json数据</h1>
<div id="div1"></div>
</body>
</html>
CheckUserServlet.java
public class CheckUserServlet extends HttpServlet {
//定义一个UserService属性
private UserService userService = new UserService();
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//System.out.println("CheckUserServlet 被调用....");
//接收ajax提交的数据
String uname = request.getParameter("uname");
System.out.println("uname= " + uname);
response.setContentType("text/html;charset=utf-8");
//到DB查询
//如果有就返回user对象,否则,返回的是null
User user = userService.getUserByName(uname);
if (user != null) {//说明用户名存在..,返回该user的json格式数据字符串
Gson gson = new Gson();
String strUser = gson.toJson(user);
response.getWriter().write(strUser);
} else {
response.getWriter().write("");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
web.xml
<servlet>
<servlet-name>CheckUserServlet</servlet-name>
<servlet-class>com.hspedu.ajax.servlet.CheckUserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CheckUserServlet</servlet-name>
<url-pattern>/checkUserServlet</url-pattern>
</servlet-mapping>
添加配置文件:
druid.properties
#key=value
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/ajaxdb?rewriteBatchedStatements=true
username=root
password=hsp
#initial connection Size
initialSize=10
#min idle connecton size
minIdle=5
#max active connection size
maxActive=50
#max wait time (5000 mil seconds)
maxWait=5000
JDBCUtilsByDruid.java
/**
* @version 1.0
* 基于druid数据库连接池的工具类
*/
public class JDBCUtilsByDruid {
private static DataSource ds;
//在静态代码块完成 ds初始化
static {
Properties properties = new Properties();
try {
//properties.load(new FileInputStream("src\\druid.properties"));
//老师解读
//1.目前我们是javaweb方式启动
//2. 所以要获取src目录下的文件,需要使用类加载器
properties.load(JDBCUtilsByDruid.class.getClassLoader()
.getResourceAsStream("druid.properties"));
ds = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
//编写getConnection方法
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
//关闭连接, 老师再次强调: 在数据库连接池技术中,close 不是真的断掉连接
//而是把使用的Connection对象放回连接池
public static void close(ResultSet resultSet, Statement statement, Connection connection) {
try {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
User.java
/**
* User类就是一个javabean/pojo/entity/domain
*/
public class User {
private Integer id;
private String username;
private String pwd;
private String email;
//必须提供一个无参构造器, 是给我们的反射使用
public User() {
}
public User(Integer id, String username, String pwd, String email) {
this.id = id;
this.username = username;
this.pwd = pwd;
this.email = email;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
BasicDAO.java
/**
* @version 1.0
* 开发BasicDAO , 是其他DAO的父类
*/
public class BasicDAO<T> { //泛型指定具体类型
private QueryRunner qr = new QueryRunner();
//开发通用的dml方法, 针对任意的表
public int update(String sql, Object... parameters) {
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
int update = qr.update(connection, sql, parameters);
return update;
} catch (SQLException e) {
throw new RuntimeException(e); //将编译异常->运行异常 ,抛出
} finally {
JDBCUtilsByDruid.close(null, null, connection);
}
}
//返回多个对象(即查询的结果是多行), 针对任意表
/**
*
* @param sql sql 语句,可以有 ?
* @param clazz 传入一个类的Class对象 比如 Actor.class
* @param parameters 传入 ? 的具体的值,可以是多个
* @return 根据Actor.class 返回对应的 ArrayList 集合
*/
public List<T> queryMulti(String sql, Class<T> clazz, Object... parameters) {
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
return qr.query(connection, sql, new BeanListHandler<T>(clazz), parameters);
} catch (SQLException e) {
throw new RuntimeException(e); //将编译异常->运行异常 ,抛出
} finally {
JDBCUtilsByDruid.close(null, null, connection);
}
}
//查询单行结果 的通用方法
public T querySingle(String sql, Class<T> clazz, Object... parameters) {
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
return qr.query(connection, sql, new BeanHandler<T>(clazz), parameters);
} catch (SQLException e) {
throw new RuntimeException(e); //将编译异常->运行异常 ,抛出
} finally {
JDBCUtilsByDruid.close(null, null, connection);
}
}
//查询单行单列的方法,即返回单值的方法
public Object queryScalar(String sql, Object... parameters) {
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
return qr.query(connection, sql, new ScalarHandler(), parameters);
} catch (SQLException e) {
throw new RuntimeException(e); //将编译异常->运行异常 ,抛出
} finally {
JDBCUtilsByDruid.close(null, null, connection);
}
}
}
UserDAO.java
//老师解读
//我们的UserDAO 继承 BaiscDAO , 并指定了User
//这时我们就可以使用BasicDAO 中的方法.
public class UserDAO extends BasicDAO<User> {
}
UserService.java
/*
老师解读 UserService 提供业务方法
,比如 getUserByName
*/
public class UserService {
//属性userDao, 方便操作数据库
private UserDAO userDAO = new UserDAO();
public User getUserByName(String username) {
//这里老师在讲解jdbc 和 满汉楼时,说的非常清楚.
User user = userDAO.querySingle
("select * from `user` where username=?", User.class, username);
return user;
}
}
2.4 原生 Ajax 请求问题分析
- 编写原生的 Ajax 要写很多的代码,还要考虑浏览器兼容问题,使用不方便。
- 在实际工作中,一般使用 JavaScript 的库(比如 Jquery) 发送 Ajax 请求,从而解决这个问题
3. JQuery 的 Ajax 请求
3.1 说明
在线文档:
https://www.w3school.com.cn/jquery/jquery_ajax_get_post.asp
3.2
$.ajax
方法
$.ajax
-
$.ajax
常用参数
● url: 请求的地址
● type : 请求的方式 get 或 post
● data : 发送到服务器的数据。将自动转换为请求字符串格式
● success: 成功的回调函数
● error: 失败后的回调函数
● dataType: 返回的数据类型 常用 json 或 text -
说明:完整的参数参看手册
3.3
$.get
请求和
$.post
请求
$.get
$.post
-
$.get
和
$.post
常用参数
url: 请求的 URL 地址
data: 请求发送到服务器的数据
success: 成功时回调函数
type: 返回内容格式,xml, html, script, json, text -
说明:
$.get
和
$.post
底层还是使用
$.ajax()
方法来实现异步请求
3.4
$.getJSON
$.getJSON
-
$.getJSON
常用参数
url: 请求发送的哪个 URL
data: 请求发送到服务器的数据
success: 请求成功时运行的函数 -
说明:
$.getJSON
底层使用
$.ajax()
方法来实现异步请求
3.5 应用实例
- 演示 jquery 发送 ajax 请求的案例
- 在输入框输入用户名
- 点击验证用户名, 服务端验证该用户名是否已经占用了, 如果该用户已经占用, 以 json格式返回该用户信息
- 假定用户名为 king , 就不可用, 其它用户名可以
-
对页面进行局部刷新, 显示返回信息
简单的思路分析.=> 程序框架图(老师画出框架图)-> 直接参考前面的分析图即可
login2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户注册</title>
<!-- 引入jquery-->
<script type="text/javascript" src="./script/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
$(function () {
//绑定事件
$("#btn1").click(function () {
//发出ajax
/**
* 老师解读
* 1. 指定参数时,需要在{}
* 2. 给参数时,前面需要指定参数名
* 3. dataType: "json" 要求服务器返回的数据格式是json
*/
// $.ajax({
// url: "/ajax/checkUserServlet2",
// type: "POST",
// data: { //这里我们直接给json, 为啥我要传日期, 为了防止浏览器缓存,有的浏览器当数据没变化时,不会发送请求
// username: $("#uname").val(),
// date: new Date()
// },
// error: function () { //失败后的回调函数
// console.log("失败~")
// },
// success: function (data, status, xhr) {
// console.log("成功");
// console.log("data=", data);
// console.log("status=", status);
// console.log("xhr=", xhr);
// //data是json对象-> 显示转成json的字符串
// $("#div1").html(JSON.stringify(data));
// //对返回的结果进行处理
// if ("" == data.username) {
// $("#myres").val("该用户名可用");
// } else {
// $("#myres").val("该用户名不可用");
// }
// },
// dataType: "json"
// })
//说明
//1.$.get() 默认是get请求,不需要指定 请求方式
//2.不需要指定参数名
//3.填写的实参,是顺序 url, data, success回调函数, 返回的数据格式
//讲解.get() 使用
// $.get(
// "/ajax/checkUserServlet2",
// {
// username: $("#uname").val(),
// date: new Date()
// },
// function (data, status, xhr) {
// console.log("$.get() 成功");
// console.log("data=", data);
// console.log("status=", status);
// console.log("xhr=", xhr);
// //data是json对象-> 显示转成json的字符串
// $("#div1").html(JSON.stringify(data));
// //对返回的结果进行处理
// if ("" == data.username) {
// $("#myres").val("该用户名可用");
// } else {
// $("#myres").val("该用户名不可用");
// }
// },
// "json"
// )
//老师说明$.post() 和 $.get() 的方式一样
//只是这时,是按照post方式发送ajax请求
// $.post(
// "/ajax/checkUserServlet2",
// {
// username: $("#uname").val(),
// date: new Date()
// },
// function (data, status, xhr) {
// console.log("$.post() 成功");
// console.log("data=", data);
// console.log("status=", status);
// console.log("xhr=", xhr);
// //data是json对象-> 显示转成json的字符串
// $("#div1").html(JSON.stringify(data));
// //对返回的结果进行处理
// if ("" == data.username) {
// $("#myres").val("该用户名可用");
// } else {
// $("#myres").val("该用户名不可用");
// }
// },
// "json"
// )
//老师说明
//1. 如果你通过jquery发出的ajax请求是get 并且 返回的数据格式是json
//2. 可以直接使用getJSON() 函数,就很简洁
$.getJSON(
"/ajax/checkUserServlet2",
{
username: $("#uname").val(),
date: new Date()
},
function (data, status, xhr) {//成功后的回调函数
console.log("$.getJSON 成功");
console.log("data=", data);
console.log("status=", status);
console.log("xhr=", xhr);
//data是json对象-> 显示转成json的字符串
$("#div1").html(JSON.stringify(data));
//对返回的结果进行处理
if ("" == data.username) {
$("#myres").val("该用户名可用");
} else {
$("#myres").val("该用户名不可用");
}
}
)
})
})
</script>
</head>
<body>
<h1>用户注册-Jquery+Ajax</h1>
<form action="/ajax/checkUserServlet2" method="post">
用户名字:<input type="text" name="username" id="uname">
<input type="button" id="btn1" value="验证用户名">
<input style="border-width: 0;color: red" type="text" id="myres"><br/><br/>
用户密码:<input type="password" name="password"><br/><br/>
电子邮件:<input type="text" name="email"><br/><br/>
<input type="submit" id="submit" value="用户注册">
</form>
<h1>返回的json数据</h1>
<div id="div1"></div>
</body>
</html>
CheckUserServlet2.java
public class CheckUserServlet2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//接收jquery发送的ajax数据
String username = request.getParameter("username");
response.setContentType("text/json;charset=utf-8");
Gson gson = new Gson();
if ("king".equals(username)) {
//要求同学们 把验证业务接入到DB
User user = new User(100, "king", "abc", "king@sohu.com");
response.getWriter().write(gson.toJson(user));
} else {
//返回一个不存在的User=> 这里老师是有设计
//将来可以通过字符串是否为空串作校验
User user = new User(-1, "", "", "");
response.getWriter().write(gson.toJson(user));
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
web.xml
<servlet>
<servlet-name>CheckUserServlet2</servlet-name>
<servlet-class>com.hspedu.ajax.servlet.CheckUserServlet2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CheckUserServlet2</servlet-name>
<url-pattern>/checkUserServlet2</url-pattern>
</servlet-mapping>
3.6 课后作业
3.6.1 作业布置
● 需求分析: 到数据库去验证用户名是否可用
说明,此处与2.3课后作业高度相似,主要是前端代码改动,其它的正常写即可!