【AJax】
1.传统开发模式的不足
传统开发模式基于浏览器数据传输功能,页面填写数据/展示数据。浏览器通过访问一个URL地址,将页面的数据提交给服务器。服务器将需要展示的数据返回给浏览器,浏览器再进行数据解析,将数据呈现在用户面前。这种模式主要依赖于浏览器的渲染功能,并且浏览器每次渲染是都是整个页面进行渲染。整个页面包含:样式文件,图片资源,DOM标签.每次浏览器渲染时都要进行重新统一渲染,重新请求一些重复的资源数据.但是实际上变化的只是页面上的数据,一些静态资源没有发生变化.这种统一的重新渲染,导致以下不足:
-
操作服务器额外的负担,因为浏览器重新请求重复数据,服务器又不记录是否发送过,导致服务器重新发送,网络/磁盘读写都造成额外的负担.
-
浏览器重复解析数据,浏览器本身也产生了额外的开销.
程序的设计者,提出了一个理念,能不能只返回想要的数据?如果做到了根据需要返回数据,减少了服务器和浏览器的负担.提出了异步交互的理念.浏览器本身在渲染时,浏览器是占用状态,无法做其它事情的.异步交互,就是指浏览器在渲染时,将渲染的等待时间利用起来,做其它行为.就像同时在做多件事情.
1.1 什么是同步交互
首先用户向HTTP服务器提交一个处理请求。接着服务器端接收到请求后,按照预先编写好的程序中的业务逻辑进行处理,比如和数据库服务器进行数据信息交换。最后,服务器对请求进行响应,将结果返回给客户端,返回一个HTML在浏览器中显示,通常会有CSS样式丰富页面的显示效果。
如果浏览器在使用中,用户都是等待状态.用户全程的参与了整个请求到数据渲染的过程.类似早期排队充值话费/打饭.
1.2 同步交互的不足
-
同步交互的不足之处,会给用户一种不连贯的体验,当服务器处理请求时,用户只能等待状态,页面中的显示内容只能是空白。
-
因为已经跳转到新的页面,原本在页面上的信息无法保存,好多信息需要重新填写
-
这种交互的方式对于服务器和浏览器而言都存在压力.存在性能的损耗
2.异步交互的概念
指发送一个请求,不需要等待返回,随时可以再发送下一个请求,即不需要等待。例如:在支付宝上充值话费.
在部分情况下,我们的项目开发中都会优先选择不需要等待的异步交互方式。将用户请求放入消息队列,并反馈给用户,系统迁移程序已经启动,你可以关闭浏览器了。然后程序再慢慢地去写入数据库去。这就是异步。异步不用等所有操作等做完,就响应用户请求。即先响应用户请求,然后慢慢去写数据库,用户体验较好.类似于多个线程在进行运行.
3.什么是AJax
Ajax是基于异步交互思想,诞生的复合的前端技术.其核心浏览器厂商约定的一套用于进行网络请求数据交互的API.浏览器厂商通过Javascript暴露了一套API,可以用于使用JS时就能通过网络从服务器获取特定的数据,然后在利用DOM技术和CSS技术,实现页面的数据变化.
由于AJax技术是浏览器厂商提供的API,浏览器厂商各自早期没有统一规范,还由于浏览器技术一直在迭代.前端技术一直在更新.市面上就出现了一些对原生ajax技术进行封装的插件.比较早期就是jQuery插件,现在比较流行的axios插件.由于现在前端推荐DOM操作,比较推崇MVVM思想,而jQuery中很大比重的都是在进行DOM操作,很多企业中,提出了去”j”的理念.
3.1 jQuery中的ajax
由于原生的Ajax存在一些不足,浏览器的兼容性,整个请求需要分为5个步骤相对繁琐.基于这样的原因.jQuery插件对原生ajax进行了封装.简化了ajax的使用.
在使用ajax时,开发者主要请求地址和请求参数及返回的数据.jQuery中的ajax在使用时,主要只需要定义请求地址,参数及返回数据的处理即可.
3.1.1 jQuery中ajax使用
-
在页面引入jQuery的JS
-
编写前端代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="js/jQuery-3.6.0.js"></script>
<style>p{color: red;}
</style>
</head>
<body><p id="msg"></p>
<button type="button" id="ajaxBtn">jQuery ajax简单案例</button><script>/* jQuery ajax 简单案例 */$("#ajaxBtn").click(function () {// 请求的urllet url = "ajax.do";// 请求参数let param = {name:"韩梅梅",age:18};$.get(url,param,function (rs) {console.log("返回数据为:",rs);$("#msg").html(rs);})});
</script>
</body>
</html>
3.1.2 jQuery中核心方法
3.1.3 ajax方法核心配置参数
3.1.3.1 ajax方法的演示
3.1.3.1.1 前端代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="js/jQuery-3.6.0.js"></script>
<style>p{color: red;}
</style>
</head>
<body><p id="msg"></p>
<button type="button" id="ajaxBtn">jQuery ajax简单案例</button>
<button type="button" id="ajax">ajax方法演示</button><script>/* jQuery ajax 简单案例 */$("#ajaxBtn").click(function () {// 请求的urllet url = "ajax.do";// 请求参数let param = {name:"韩梅梅",age:18};$.get(url,param,function (rs) {console.log("返回数据为:",rs);$("#msg").html(rs);})});/* 演示ajax 方法 */$("#ajax").click(function () {let m = 10;let settings = {url:"jquery.do",// 请求地址type:"post",// 请求方法timeout:1000,// 超时时间 1秒data:{ // 请求参数name:"韩梅梅",age:18},async:false,// 是否异步 如果是异步 则 ajax 函数没有执行完成就能执行之后的程序.如果非异步则必须等待ajax程序执行完成才能执行之后的程序// 如果ajax函数中的数据要参与之后程序的运算,必须设置非异步 falsedataType:"json", // 期望返回的数据类型,一般浏览器会将返回的数据当做自己期望的类型,如果不是期望类型则程序会异常,通过火狐浏览器查看beforeSend:function () {console.log("我要请求了!!!!")//console.log("加载中....在转圈圈...")},success:function (data,req,xh) { // 请求成功时调用的方法console.log(data) // 返回的数据console.log(req) // 消息console.log(xh) // XMLHttpRequest 对象// 将数据放入到 p 标签$("#msg").html(data);// 改变 m的值m = m + 100;},complete:function () {// 标识请求完成调用的函数 不论成功还是失败都会调用console.log("取消转圈圈...")},error:function (xh,status) { // error 两种情况触发 :1. url地址错误 2.服务器内部程序异常console.log("xh:",xh) // ajax 对象console.log("status:",status) // 错误信息}};$.ajax(settings);console.log("m的值:",m);});
</script>
</body>
</html>
3.1.3.1.2 后端代码
package com.powernode;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("/jquery.do")
public class JQueryAjaxServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {/* try {// 线程休眠 5 秒Thread.sleep(5000);} catch (InterruptedException e) {throw new RuntimeException(e);}*/String name = req.getParameter("name");String age = req.getParameter("age");System.out.println(name +" " +age);PrintWriter writer = resp.getWriter();/* html head body p style */writer.print("{\"name\":\"Hello jQuery ajax\"}");writer.flush();writer.close();}
}
3.1.4 get/post方法演示
在实际使用中,开发者只关注2个点,请求信息和返回的数据.jQuery提供一些方法对ajax方法进行简化,如:get(url,[param],function)/post(url,[param],function).分别表示get类型的异步请求和post异步请求(比较常用).
3.1.4.1 演示案例
/*** 演示 get 方法*/
$("#get").click(function () {$.get("jquery.do",{name:"韩梅梅",age:18},function (rs) {console.log(rs)$("#msg").html(rs);})
});
/*** 演示 post 方法*/
$("#post").click(function () {$.post("jquery.do",{name:"韩梅梅",age:18},function (rs) {console.log(rs)$("#msg").html(rs);})
});
3.2 axios的使用
首先要在页面引入axios的js插件.参考:axios中文网.
3.2.1 axios应用
3.2.1.1 后端代码
package com.powernode;import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
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("/axios.do")
public class AxiosServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("UTF-8");
// ServletInputStream inputStream = req.getInputStream();
// byte[] b = new byte[1024];
// int len = inputStream.read(b);
// System.out.println(new String(b,0,len,"UTF-8"));String name = req.getParameter("name");String age = req.getParameter("age");// 将字符串转 对象System.out.println(name +" " +age);PrintWriter writer = resp.getWriter();/* html head body p style */writer.print("{\"name\":\"Hello axios ajax\"}");writer.flush();writer.close();}
}
3.2.1.2 前端代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="js/axios.js"></script>
</head>
<body>
<p id="msg"></p>
<button id="get">不带参数的get请求</button>
<button id="getParam">带参数的get请求</button>
<button id="post">post请求</button>
<script>/*** 演示 axios 的get 请求* axios 默认就是 get 请求*/document.getElementById("get").onclick = function () {axios.get("axios.do")// 请求完成时调用的函数.then(function (response) {// 整个响应数据对象console.log(response);// 默认的axios的配置信息console.log(response.config);// service 方法返回的具体的数据console.log(response.data);// 返回的响应头信息console.log(response.headers);// http 响应码console.log(response.status);}) // 请求发生异常时调用的函数.catch(function (error) {console.log(error);});}/*** 带参数的get 请求*/document.getElementById("getParam").onclick = function () {axios.get("axios.do",{params:{name:"韩梅梅",age:18}})// 请求完成时调用的函数.then(function (response) {// 整个响应数据对象console.log(response);// 默认的axios的配置信息console.log(response.config);// service 方法返回的具体的数据console.log(response.data);// 返回的响应头信息console.log(response.headers);// http 响应码console.log(response.status);}) // 请求发生异常时调用的函数.catch(function (error) {console.log(error);});}/*** post 请求*/document.getElementById("post").onclick = function () {axios.post("axios.do",{name:"韩梅梅",age:18},{// 为 post 请求 兼容表单 URL参数编码问题transformRequest: [function (data, headers) {console.log(" 数据格式处理.....")console.log(data)// 对 data 进行任意转换处理// {name:"hanmeimei",age:18} ---> name=韩梅梅&age=18let formData = new Array();// 循环对象for(name in data){// item 对象中的属性 : name age// 根据动态的属性名 获取对应的值let value = data[name];console.log(name,"=",value)formData.push(name+"="+value)}console.log(formData)formData = formData.join("&");console.log(formData)return formData;}],})// 请求完成时调用的函数.then(function (response) {// 整个响应数据对象console.log(response);// 默认的axios的配置信息// console.log(response.config);// service 方法返回的具体的数据//console.log(response.data);// 返回的响应头信息//console.log(response.headers);// http 响应码//console.log(response.status);}) // 请求发生异常时调用的函数.catch(function (error) {console.log(error);});}</script></body>
</html>
4.浏览器跨域访问
在Ajax请求中,JS是基于浏览器进行网络通信的.这种功能必须依附浏览器,出于安全的考虑,浏览器会对JS通信的数据进行检查.浏览器对数据检查通过之后,才会将通信数据移交给JS程序.浏览器最基本检查策略叫同源策略.是一种最基本安全保护机制
4.1 同源策略
在网络访问中,必须存在3种数据:协议/域名/端口.如果3种数据一致就标识同源访问,如果不一致就是非同源访问.默认浏览器只支持同源访问.
以下就是非同源访问的浏览器异常信息.也被称之为跨域访问.
当前浏览器访问地址:http://localhost:8080/ajax_crud/index.html
ajax的访问地址:http://127.0.0.1:8080/ajax_crud/user.do
由于当前浏览器地址的域名:localhost,但是ajax的地址是127.0.0.1虽然都是标识同一个地址,但是浏览器检测时认为和自己的不一致,所以进行抛出了异常,认为存在跨域访问.
4.2 跨域解决
跨域问题解决方案比较多,例如:jsonp,服务器允许跨域访问设置.浏览器既然会检查数据,服务器返回数据时,直接通知浏览器本次访问是允许跨域访问的.需要通过响应头通知浏览器.
// 允许跨域访问 * 任何访问源
resp.addHeader("Access-Control-Allow-Origin","*");
5.Ajax综合案例
利用ajax 实现增/删除/查/改.
5.1 后端代码
5.1.1 servlet
package com.powernode.servlet;import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.powernode.dao.UserDao;
import com.powernode.domain.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.IOException;
import java.io.PrintWriter;
import java.util.List;/*** 在servlet中 默认只有service 能够提供服务* 那么出现 同类请求存在多个 例如 : 用户的请求 新增 删除 修改 查询 等等 难道创建多个 ?* 通过设计的方式解决问题:* 每个操作中,要求额外传递一个参数 标识是什么操作. 例如 : 如果是新增 则 传递 service = add* 删除 则传递 service = delete* 修改 则传递 service = update* 查询 则传递service = query* 在service 方法中 根据 service 参数的值 进行 分条件调用*/
@WebServlet("/user.do")
public class UserServlet extends HttpServlet {UserDao userDao = new UserDao();@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("UTF-8");String service = req.getParameter("service");if (StrUtil.equals(service,"add")){// 处理 新增的方法add(req,resp);}else if (StrUtil.equals(service,"delete")){// 处理 新增的方法delete(req,resp);}else if (StrUtil.equals(service,"query")){// 处理 新增的方法query(req,resp);}else if (StrUtil.equals(service,"update")){// 处理 新增的方法update(req,resp);}}/*** 处理更新请求* @param req* @param resp*/private void update(HttpServletRequest req, HttpServletResponse resp) throws IOException {String id = req.getParameter("id");String realname = req.getParameter("realname");String username = req.getParameter("username");String password = req.getParameter("password");userDao.update(Integer.parseInt(id),username,password,realname);// 使用UTF-8格式处理字节数据resp.setCharacterEncoding("UTF-8");PrintWriter writer = resp.getWriter();//输出数据writer.write("success");writer.flush();writer.close();}/*** 处理查询请求* @param req* @param resp*/private void query(HttpServletRequest req, HttpServletResponse resp) throws IOException {// 获取输入的姓名String realname = req.getParameter("realname");List<User> users = userDao.selectAll(realname);// 使用JSON格式输出// 表示返回json格式数据resp.setContentType("text/json;charset=utf-8");// 使用UTF-8格式处理字节数据resp.setCharacterEncoding("UTF-8");PrintWriter writer = resp.getWriter();// 将 List 转 JSON字符串String data = JSON.toJSONString(users);//输出数据writer.write(data);writer.flush();writer.close();}/*** 处理删除请求* @param req* @param resp*/private void delete(HttpServletRequest req, HttpServletResponse resp) throws IOException {String id = req.getParameter("id");userDao.delete(Integer.parseInt(id));resp.setCharacterEncoding("UTF-8");PrintWriter writer = resp.getWriter();//输出数据writer.write("success");writer.flush();writer.close();}/*** 处理新增请求* @param req* @param resp*/private void add(HttpServletRequest req, HttpServletResponse resp) throws IOException {String realname = req.getParameter("realname");String username = req.getParameter("username");String password = req.getParameter("password");userDao.add(username,password,realname);// 使用UTF-8格式处理字节数据resp.setCharacterEncoding("UTF-8");PrintWriter writer = resp.getWriter();//输出数据writer.write("success");writer.flush();writer.close();}
}
5.1.2 dao
package com.powernode.dao;import cn.hutool.core.util.StrUtil;
import com.powernode.domain.User;import java.util.List;/*** 用户表操作类*/
public class UserDao extends BaseDao {/*** 新增用户* @param username* @param password* @param realname*/public void add(String username, String password,String realname) {String sql = "insert into user (username,password,realname) value(?,?,?)";super.executeUpdate(sql,username,password,realname);}/*** 删除用户* @param id*/public void delete(Integer id) {String sql = "delete from user where id=?";super.executeUpdate(sql,id);}/*** 修改用户* @param id* @param username* @param password* @param realname*/public void update(Integer id, String username, String password,String realname) {String sql = "update user set username = ?,password=? ,realname=? where id = ?";super.executeUpdate(sql,username,password,realname,id);}/*** 查询所有的用户* @param realname* @return*/public List<User> selectAll(String realname) {// TODO 多个条件 该如何拼接 动态SQLString sql = "select id,username,password,realname from user";if (StrUtil.isNotBlank(realname)){sql = sql +" where realname like '%"+realname+"%' ";}return super.executeQueryList(sql,User.class);}
}
5.2 列表页面
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>用户列表</title>
</head>
<body>
<p><input id="realname"/><button id="searchBtn">查询</button>
</p>
<hr>
<a href="add.html">新增</a>
<hr>
<table id="dataTable"><tr><td>ID</td><td>登录名</td><td>密码</td><td>姓名</td><td>操作</td></tr>
</table>
<script src="js/jQuery-3.6.0.js"></script>
<script>// 全局性的存储 当前table 用户信息let globalUser ;/*** 渲染表格*/function renderTable() {// 获取搜索的关键词let realname = $("#realname").val();$.get("user.do", {service: "query", realname: realname}, function (rs) {// 数组长度如果为 0 表示没有数据if (rs.length == 0) {// 结束程序return false;}globalUser = rs;// 获取表格dom 对象let table = $("#dataTable");// 清空表格// 获取所有 tr 但是 索引大于 0$("tr:gt(0)").remove();for (let user of rs) {let id = user.id;let username = user.username;let password = user.password;let realname = user.realname;tr ="<tr><td>"+id+"</td>"+"<td>"+username+"</td>"+"<td>"+password+"</td>"+"<td>"+realname+"</td><td><button οnclick='del("+id+")'>删除</button><button οnclick='update("+id+")'>修改</button></td></tr>"table.append(tr);}});}$("#searchBtn").click(function () {renderTable();});renderTable();/*** 删除方法* @param id*/function del(id) {$.get("user.do",{service:"delete",id:id},function (rs) {if (rs == "success"){renderTable();return false;}alert("删除失败")})}function update(id) {// 循环所有的用户for (let user of globalUser) {// 如果id一直 说明 就是要修改的用户的if (user.id == id){// user 本身是 object// sessionStorage 存储的 字符串类型// JSON.stringify(user) 将对象转化为 json 字符串sessionStorage.setItem("user",JSON.stringify(user))}}// 跳转到更新页面location.href='update.html';}
</script>
</body>
</html>
**5.3 新增列表**```c```c
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form ><p>姓名:<input name="realname" id="realname" /></p><p>用户名:<input name="username" id="username" /></p><p>密码:<input name="password" id="password" /></p><button type="button" id="subBtn">提交</button><button type="button" id="back">返回</button>
</form>
<script src="js/jQuery-3.6.0.js"></script>
<script>$("#subBtn").click(function () {let realname = $("#realname").val();let username = $("#username").val();let password = $("#password").val();$.post("user.do",{service:"add",realname:realname,username:username,password:password},function (rs) {// 如果返回值 success 表示添加成功// 返回到 index页面if (rs == 'success'){location.href = "index.html";return false;}alert("添加失败!");})});$("#back").click(function () {location.href = "index.html";});
</script>
</body>
</html>
**5.4 修改页面**```c
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form ><p>姓名:<input name="realname" id="realname" /></p><p>用户名:<input name="username" id="username" /></p><p>密码:<input name="password" id="password" /></p><button type="button" id="subBtn">提交</button><button type="button" id="back">返回</button>
</form>
<script src="js/jQuery-3.6.0.js"></script>
<script>let user ;//向表单填充数据function initForm() {user = sessionStorage.getItem("user");console.log(user)// 将字符串转对象user = JSON.parse(user);$("#realname").val(user.realname);$("#username").val(user.username);$("#password").val(user.password);}initForm();$("#subBtn").click(function () {let realname = $("#realname").val();let username = $("#username").val();let password = $("#password").val();$.post("user.do",{service:"update",id:user.id,realname:realname,username:username,password:password},function (rs) {// 如果返回值 success 表示添加成功// 返回到 index页面if (rs == 'success'){location.href = "index.html";return false;}alert("修改失败!");})});$("#back").click(function () {location.href = "index.html";});
</script>
</body>
</html>