1.关于ajax那些不得不知道的事。
ajax:又称为javaScript与服务端交互的一种手段,实际上并不存在ajax这种技术,它是通过javaScript相关技术来对数据进行操作,又称为局部刷新技术。
何为局部刷新:局部刷新就是在不用修改页面的整体内容只需要刷新内部的不小部分内容来实现数据的改变,这种方式的优点就是减少页面卡顿,以及在不影响原有数据加载的情况下,对页面进行数据加载,可以理解为是在用户请求服务器时,服务器同时又开启了一个子线程,主线程在执行整体页面的加载时,子线程也在进行自己的数据加载操作。这就是异步操作。
1.我们先通过一个简单案例来向大家介绍ajax的基本操作,完成异步请求与服务端进行交互:
在演示之前我们需要知道一个对象XMLHttpRequest对象
XMLHttpRequest:这个对象是javaScript内部封装的一个对象,它就是用来执行ajax请求的。
它里边的常用方法有:
open():用来封装参数信息,它里边常用的三个参数分别是
method:请求方式,uri:请求路径—GET请求时可以拼接参数信息,post请求时不可以拼接参数信息,ayanc:是否支持异步,默认为true。
send():用来发送请求,当时用post请求时,我们必须将参数封装在send方法中,然后执行ajax请求。在post请求发送参数时,必须设置请求头中的content-type属性。例如:
// 2.设置请求头信息xmlHttpRequest.setRequestHeader("content-type","application/x-www-form-urlencoded");
onreadystatechange:绑定回调函数,当请求通过send方法执行到对应路径的serlvet后,返回的数据时就会调用这个回调函数,执行回调函数中的内容,一般来说回调函数必须写在send方法之前。
好了,接下来就进入实地操作环节:
2.ajax的基本操作
实地案例1:局部刷新,实现查询BMI系数
操作分析:我们需要做一个表单,在我们点击计算按钮时,会发送ajax请求到服务器,服务器通过计算将结果返回到ajax的jsp页面的回调函数中,我们在回调函数中将返回回来的数据渲染到页面中。
演示步骤:
(1)前置操作
制作表单,并给按钮绑定单击事件:doAjax()
<center><p style="color: cornflowerblue;size: 50px">全局刷新计算bmi</p><div><div id="mydata">等待加载数据</div>姓名:<input type="text" id="name"><br>体重(公斤):<input type="text" id="w"><br>身高(米):<input type="text" id="h"><br><input type="button" value="计算bmi" onclick="doAjax()"></div></center>
(2)ajax操作四部曲
在js代码块中创建一个doAjax()函数来执行ajax方法
ajax方法的过程一般分为一下4步
1、创建异步对象
2.绑定回调函数
3.初始化请求参数
4.发起请求
接下来我们一步步的完成以上操作
1.我们需要创建javaScript中的执行ajax的内置对象XMLHttpRequest,
// 1.创建异步对象var xmlHttp=new XMLHttpRequest();
2.我们需要绑定回调函数
// 2.绑定事件xmlHttp.onreadystatechange=function () {// 处理服务器端返回的数据,更新当前页面// alert("XMLHttpRequest"+xmlHttp+"---status"+status);if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {// alert(parm)// alert(xmlHttp.responseText);/*获取响应返回的数据*/var data = xmlHttp.responseText;// 更新dom对象的页面数据document.getElementById("mydata").innerText=data;}}
3.我们需要初始化请求参数:记住我们在初始化请求参数时,并没有发起ajax操作
// 3.初始请求数据// 获取参数信息var name= document.getElementById("name").value;var w= document.getElementById("w").value;var h=document.getElementById("h").value;var parm="name="+name+"&w="+w+"&h="+h;xmlHttp.open("get","bmiAjax?"+parm,true);
4.发送请求
// 4.发起请求xmlHttp.send();
(3)servlet处理逻辑
接下来就是做servlet中的代码,因为无操作难度,直接附上
/** @Author liu-miss* @Description 通过ajax发送异步请求* @Date 14:20 2021/5/9**/@WebServlet(name = "BmiServlet", value = "/bmiAjax")public class BmiAjaxServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 获取请求参数String name = request.getParameter("name");String weight = request.getParameter("w");String height = request.getParameter("h");// 格式化double userweight=Double.parseDouble(weight);double userheight=Double.parseDouble(height);// 调用service层对象处理数据IBmiService is=new IBmiServiceImp();double bmiCount = is.getBmiCount(userweight, userheight);String msg="";if (bmiCount<=18.5){msg="您比较瘦";}else if (bmiCount>=18.5 && bmiCount<=23.9){msg="您的身体正常";}else if (bmiCount>24 && bmiCount<=27 ){msg="您的身体比较胖";}else {msg="您的身体肥胖";}PrintWriter printWriter=response.getWriter();printWriter.println(msg);printWriter.flush();printWriter.close();}}
自此我们就完成了一个简单的BMI系数计算的ajax操作.
实现效果:
3.三级联动下拉列表框案例实现
接下来我们实现一个生活中经常会遇到的一个案例:省份,市区,县的三级下拉列表框,并且使用三种不同的数据格式来封装数据,分析三种方式的优势与劣势。
三种方式分别是:文本格式,xml格式,json格式
实现效果:
制作前我们先分析这个案例的实现过程:
首先,我们需要
建立三张表分别是省份表:省份编号,省份名称
城市表:城市编号,城市名称,城市所属省份编号
县/区表:县的编号,县的名称,县所属城市编号
这是sql表的附件,供各位自己下载。
pca.sql
注意:下面这个案例的回调函数都是封装过后的回调函数
接下来我们需要做的是,创建sql表对应的bean类,以及数据库连接的dbcp工具类
为了让各位快速进行ajax的实际操作,这部分代码我直接放出来
1.案例的前置工作
省份表模型类
package com.xiaoqi.ajax.domain;/*** @Author Rookie Coder* @Description* @Date**/public class Province {private String provinceID;private String province;public Province() {}public Province(String provinceID, String province) {this.provinceID = provinceID;this.province = province;}public String getProvinceID() {return provinceID;}public void setProvinceID(String provinceID) {this.provinceID = provinceID;}public String getProvince() {return province;}public void setProvince(String province) {this.province = province;}@Overridepublic String toString() {return "Province{" +"provinceID='" + provinceID + '\'' +", province='" + province + '\'' +'}';}}
城市表模型类
package com.xiaoqi.ajax.domain;/*** @Author Rookie Coder* @Description* @Date**/public class City {private String cityID;private String city;private String father;public City() {}public City(String cityID, String city, String father) {this.cityID = cityID;this.city = city;this.father = father;}public String getCityID() {return cityID;}public void setCityID(String cityID) {this.cityID = cityID;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public String getFather() {return father;}public void setFather(String father) {this.father = father;}@Overridepublic String toString() {return "City{" +"cityID='" + cityID + '\'' +", city='" + city + '\'' +", father='" + father + '\'' +'}';}}
县/区表模型类
package com.xiaoqi.ajax.domain;/*** @Author Rookie Coder* @Description* @Date**/public class Area {private String areaID;private String areas;private String father;public Area(String areaID, String areas, String father) {this.areaID = areaID;this.areas = areas;this.father = father;}public Area() {}public String getAreaID() {return areaID;}public void setAreaID(String areaID) {this.areaID = areaID;}public String getAreas() {return areas;}public void setAreas(String areas) {this.areas = areas;}public String getFather() {return father;}public void setFather(String father) {this.father = father;}@Overridepublic String toString() {return "Area{" +"areaID='" + areaID + '\'' +", areas='" + areas + '\'' +", father='" + father + '\'' +'}';}}
数据库连接类
package com.xiaoqi.ajax.util;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.sql.*;import java.util.ArrayList;import java.util.List;/*** @Author Rookie Coder* @Description* @Date**/public class DBCPUtil {static {try {Class.forName("com.mysql.jdbc.Driver");} catch (ClassNotFoundException e) {e.printStackTrace();}}/** @Author liu-miss* @Description 获取数据库连接* @Date 15:49 2021/7/12* @Param []* @return java.sql.Connection**/private Connection getConnection() {Connection connection=null;String username= "root";String password="140489lu";String url="jdbc:mysql://localhost:3306/ajax";try {if (connection==null){connection = DriverManager.getConnection(url,username,password);}} catch (SQLException throwables) {throwables.printStackTrace();}return connection;// try {// Context context = new InitialContext();// DataSource dataSource = (DataSource) context.lookup("java:/comp/env/dbcp/servlet");// System.out.println("进入连接池");// return dataSource.getConnection();// } catch (NamingException | SQLException e) {// System.out.println("出现异常");// e.printStackTrace();// }// return null;}/** @Author liu-miss* @Description 关闭连接方法* @Date 15:53 2021/7/12* @Param [connection, pst, rs]* @return void**/private void closeAll(Connection connection, PreparedStatement pst, ResultSet rs) {try {if (rs!=null){rs.close();}} catch (SQLException throwables) {throwables.printStackTrace();}try {if (pst!=null){pst.close();}} catch (SQLException throwables) {throwables.printStackTrace();}try {if (connection!=null){connection.close();}} catch (SQLException throwables) {throwables.printStackTrace();}}/** @Author liu-miss* @Description 增删改方法* @Date 17:09 2021/7/12* @Param [sql, params]* @return int**/public int update(String sql, Object...params ){Connection connection=null;PreparedStatement pst=null;try {connection = getConnection();pst=connection.prepareStatement(sql);if (params!=null && params.length>0){for (int i = 0; i < params.length; i++) {// System.out.println(params[i]);pst.setObject(i+1,params[i]);}}int i = pst.executeUpdate();return i;} catch (SQLException throwables) {throwables.printStackTrace();}finally {closeAll(connection,pst,null);}return -1;}public Object query(String sql,Object...params){Connection connection=null;PreparedStatement pst=null;ResultSet rs=null;try {connection=getConnection();pst = connection.prepareStatement(sql);if (params!=null && params.length>0){for (int i = 0; i < params.length; i++) {pst.setObject(i+1,params[i]);}}rs = pst.executeQuery();if (rs.next()){System.out.println("------");System.out.println(rs.getObject(1));System.out.println(rs.getObject(1).getClass());System.out.println("------");return rs.getObject(1);}} catch (SQLException throwables) {throwables.printStackTrace();}return null;}public <T> List<T> query(String sql,Class<T> c,Object...params){Connection connection=null;PreparedStatement pst=null;ResultSet rs=null;List<T> list=new ArrayList<>();try {connection=getConnection();pst = connection.prepareStatement(sql);if (params!=null && params.length>0){for (int i = 0; i < params.length; i++) {pst.setObject(i+1,params[i]);}}rs = pst.executeQuery();// 通过反射封装结果集// 获取列数ResultSetMetaData metaData = rs.getMetaData();int columnCount = metaData.getColumnCount();System.out.println("列数====="+columnCount);while (rs.next()){try {// 创建泛型对象T t = c.getConstructor().newInstance();for (int i = 0; i < columnCount ; i++) {String columnName = metaData.getColumnLabel(i+1);System.out.println("columnName"+columnName);String methodName = "set" + columnName.substring(0,1).toUpperCase()+ columnName.substring(1);System.out.println("methodName"+methodName);Method method = c.getMethod(methodName,String.class);System.out.println("method"+method);method.invoke(t,rs.getObject(columnName));}list.add(t);} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();}}} catch (SQLException throwables) {throwables.printStackTrace();}return list;}}
2.ajax实际操作部分:
1.我们需要先制作三个下拉框,并且赋予id值,方便后边获取下拉框中的属性值
<select id="province" onchange="getCity()"><option>--请选择省份--</option></select>省<select id="city" onchange="getArea()"><option>--请选择市--</option></select>市<select id="area"><option>--请选择区--</option></select>区
下拉框为了美观点,我设置了一点样式
<style>select{width: 200px;height: 30px;line-height: 30px;}</style>
2.我们需要定义在页面加载完成后就让省份的下拉框中有内容,方便用户直接选取,因此我们需要用到window.onload函数来执行第一个ajax操作,依旧是原来的四步ajax操作
(1)做查询省份的ajax操作:
第一步:创建XMLHttpRequest对象
第二步:封装请求信息
第三步:绑定回调函数
第四步:发送请求
这几步大家应该很熟悉了,下面是查找省份的ajax代码部分
// 1.创建xmlHttpRequest对象let xmlHttpRequest = new XMLHttpRequest();window.onload=function(){// 1.传入参数信息xmlHttpRequest.open("post","selectPAC")// 2.设置请求头信息xmlHttpRequest.setRequestHeader("content-type","application/x-www-form-urlencoded");// 3.绑定事件xmlHttpRequest.onreadystatechange = doProvince;// 4.发送请求并传入参数信息xmlHttpRequest.send("action=province");}function doProvince() {if (xmlHttpRequest.readyState==4){// 1.获取响应回来的值var data = xmlHttpRequest.responseText;// console.log(data);// 2,裁剪数据var p =data.split(";");var sele = document.getElementById("province");for (let i = 1; i <p.length ; i++) {var pro = p[i].split(",");sele.innerHTML = sele.innerHTML + '<option value="'+pro[0]+'">'+pro[1]+'</option>';}}}
当页面加载完成时,这个函数会向selectPAC这个路径的资源,发送请求并且携带请求参数.
(2)使用action参数分别调用不同的处理方法格式
在s处理ajax的ervlet中,我们为了方便,会向这个servlet传递一个action参数,通过这个参数信息,调用不同的ajax请求操作,下边是通过action参数的值分别调用不同处理ajax请求的代码
@WebServlet("/selectPAC")public class AjaxSlectPCA extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String action = req.getParameter("action");if (action==null || "".equals(action)){return;}if ("province".equals(action)){selectProvince(req,resp);}if ("city".equals(action)){selectCity(req,resp);}if ("area".equals(action)){selectArea(req,resp);}}}
(3)使用文本格式传递省份数据
首先分析:我们在封装一个数据时,需要将数据封装成一种具有某种规则的数据,只有这样我们才能将这个数据中的每一段数据都分离开来,因此我们在用文本封装数据时,我使用的方式是,每一个对象之间用 分号 隔开,每一个对象的属性之间用 逗号 隔开.
接下来我们要做第一个ajax操作,查询省所有的省份,并且返回,我们使用文本格式来进行这个操作
而我们需要做的就是将每个对象用” ; 隔开”,用逗号隔开属性.
我们将查询到的省份使用字符串拼接的方式,将所有的数据循环拼接出来,返回给回调函数.
private void selectProvince(HttpServletRequest req, HttpServletResponse resp) throws IOException {String sql = "select provinceID,province from province";resp.setContentType("text/html;charset=utf-8");PrintWriter writer = resp.getWriter();DBCPUtil dbcpUtil =new DBCPUtil();List<Province> query = dbcpUtil.query(sql, Province.class);// 封装listStringBuffer sb = new StringBuffer();sb.append("-1,--请选择省份--");for (Province p:query) {sb.append(";");sb.append(p.getProvinceID());sb.append(",");sb.append(p.getProvince());}writer.println(sb);writer.flush();writer.close();}
(4)回调函数处理返回的文本数据
步骤:
1 我们需要先通过XMLHttpRequest对象中的responseTest这个方法可以获取到servlet返回的数据,
2 我们将获取到的文本数据使用分隔函数分隔开,然后再将它写到页面中去
分析难点问题:
为什么页面中只有一个对象的name属性一直在,原因是通过循环写出去的内容,他将所有的对象不断替代,最后所有的对象就是最后一个对象了
解决方法: 代码第11行
sele.innerHTML = sele.innerHTML + ‘‘;
在循环中让他每次在拼接时,在拼接上上一次的内容就可以获取到所有的省份元素了.
function doProvince() {if (xmlHttpRequest.readyState==4){// 1.获取响应回来的值var data = xmlHttpRequest.responseText;// console.log(data);// 2,裁剪数据var p =data.split(";");var sele = document.getElementById("province");for (let i = 1; i <p.length ; i++) {var pro = p[i].split(",");sele.innerHTML = sele.innerHTML + '<option value="'+pro[0]+'">'+pro[1]+'</option>';}}}
(5)使用xml格式传递城市数据
具体操作都是大同小异,细节不同点是一个在servlet的数据拼接部分,一个是在ajax的回调函数的处理部分,因为xml格式传递数据已经基本不在使用了,以介绍为主
xmlservlet中的代码:
private void selectCity(HttpServletRequest req, HttpServletResponse resp) throws IOException {String provinceID = req.getParameter("provinceID");resp.setContentType("text/xml;charset=utf-8");String sql = "select cityID,city,father from city where father=?";DBCPUtil dbcpUtil =new DBCPUtil();PrintWriter writer = resp.getWriter();List<City> query = dbcpUtil.query(sql, City.class, provinceID);StringBuffer sb = new StringBuffer();sb.append("<Citys>");for (City c: query) {sb.append("<city>");sb.append("<id>"+c.getCityID()+"</id>");sb.append("<name>"+c.getCity()+"</name>");sb.append("</city>");}sb.append("</Citys>");writer.write(sb.toString());writer.flush();writer.close();}
(6)使用json个数传递县/区数据
1.什么是JSON,json是一种数据格式,通常用来封装后台数据,传递给前台,通过浏览器解析出来,渲染到页面中,通常用来封装一些复杂的 数据类型。而我们手动写json格式的数据的话,会非常的麻烦,因此我们选用第三方jar包来完成:通常使用的封装json格式数据的jar包有:gson(由谷歌发行的),json(),fastjson 。。等
第一步:我们需要加入第三方jar包依赖。详细依赖请看我写的另外一篇关于学习的所有依赖文章中。
本次我们使用的是gson依赖:
<dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.2</version></dependency>
在这个jar包中,为我们提供了很多方法例如:toJson方法,toObject方法等等。。
我们要做的第二步是创建Gson对象,调用Gson对象的toJson方法,这个方法甚至可以将一个集合直接封装为json格式,详细代码:
private void selectArea(HttpServletRequest req, HttpServletResponse resp) throws IOException {resp.setContentType("text/json;charset=utf-8");PrintWriter writer = resp.getWriter();String cid = req.getParameter("cid");System.out.println("cid====================================="+cid);String sql = "select areaID,areas,father from areas where father = ?";DBCPUtil dbcpUtil = new DBCPUtil();List<Area> query = dbcpUtil.query(sql, Area.class, cid);System.out.println("-----------------------");System.out.println(query);System.out.println("-----------------------");Gson gson = new Gson();String json = gson.toJson(query);writer.println(json);writer.flush();writer.close();}
(5)回调函数处理json格式的文本数据
在javaScript中有一个内置的JSON对象,它里边有一个parse方法,可以通过这个方法解析出json数据,而json数据中的每一个元素都是以对象形式存在的,因此可以直接通过对象.属性的方式获取到值
这里注意:
json中每一个对象的值的key都是封装的bean的属性值。
function doArea(){let elementById = document.getElementById("area");//alert(2)if (xmlHttpRequest.readyState==4){// alert(1)var data = xmlHttpRequest.responseText;// alert(data)var json = JSON.parse(data);//console.log(json);elementById.innerHTML="";for (let i = 0; i < json.length; i++) {elementById.innerHTML = elementById.innerHTML+'<option value=json[i].areaID">'+json[i].areas+'</option>';}}
三种格式处理数据的优缺点分析:
文本格式可以处理简单类型的数据,无法处理复杂类型数据,比如一个对象中有一个属性是另外一个类的对象属性。
xml格式的优势在于可以清晰的看出数据的整个层次,缺点就是拼接麻烦,数据利用率低、
json格式的优势在于可以封装复杂类型的数据,缺点暂时没有发现。。。
=============================================================
===============================================================
第二次更新:
4.使用Jquery提供的函数完成
上述案例还可以使用在jQuery中已经定义好的几个函数来完成,接下来我就用三种不同的方法来分别完成省市区的ajax操作
请千万不要眨眼睛哦
jsp页面部分
<%--Created by IntelliJ IDEA.User: 小柒的JavaDate: 2021/7/20Time: 10:03To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head><title>ajax局部刷新</title><script src="webjars/jquery/3.5.1/jquery.min.js"> </script><script>$(function () {$.get("selectPAC2",{"action":"province"},function (resp) {$.each(resp,function (i,n){$("#prov").append('<option value="'+n.provinceID+'">'+n.province+"</option>")})},"json")$("#prov").change(function () {$.getJSON("selectPAC2",{"action": "city","provinceID":$("#prov").val() },function (resp) {$("#city").empty();$.each(resp,function (i,n) {$("#city").append('<option value="'+n.cityID+'">'+n.city+"</option>");})})})$("#city").change(function () {$.ajax({url:"selectPAC2",type:"get",data:{"action":"area","cid" : $("#city").val()},dataType:'json',success:function (resp) {console.log(resp);$("#area").empty();$.each(resp,function (i,n) {$("#area").append('<option value="'+n.areaID+'">'+n.areas+"</option>");})}})})});</script></head><body><select id="prov"></select>省<select id="city"></select>城市<select id="area"></select>区</body></html>
servlet部分
/*** @Author Rookie Coder* @Description* @Date**/@WebServlet("/selectPAC2")public class JQueryAjaxSlectPCA extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String action = req.getParameter("action");System.out.println(action);if (action==null || "".equals(action)){return;}if ("province".equals(action)){selectProvince(req,resp);}if ("city".equals(action)){selectCity(req,resp);}if ("area".equals(action)){selectArea(req,resp);}}private void selectArea(HttpServletRequest req, HttpServletResponse resp) throws IOException {resp.setContentType("text/json;charset=utf-8");PrintWriter writer = resp.getWriter();String cid = req.getParameter("cid");System.out.println(cid);String sql = "select areaID,areas,father from areas where father = ?";DBCPUtil dbcpUtil = new DBCPUtil();List<Area> query = dbcpUtil.query(sql, Area.class, cid);System.out.println(query);Gson gson = new Gson();String json = gson.toJson(query);writer.println(json);writer.flush();writer.close();}private void selectCity(HttpServletRequest req, HttpServletResponse resp) throws IOException {String provinceID = req.getParameter("provinceID");resp.setContentType("text/json;charset=utf-8");String sql = "select cityID,city,father from city where father=?";DBCPUtil dbcpUtil =new DBCPUtil();PrintWriter writer = resp.getWriter();System.out.println("000000000000000000");List<City> query = dbcpUtil.query(sql, City.class, provinceID);System.out.println("000000000000000000");writer.write(new Gson().toJson(query));writer.flush();writer.close();}private void selectProvince(HttpServletRequest req, HttpServletResponse resp) throws IOException {String sql = "select provinceID,province from province";resp.setContentType("text/json;charset=utf-8");PrintWriter writer = resp.getWriter();DBCPUtil dbcpUtil =new DBCPUtil();List<Province> query = dbcpUtil.query(sql, Province.class);writer.println(new Gson().toJson(query));writer.flush();writer.close();}}
最后祝愿各位学业有成,工作顺利!!!
