AJAX 介绍

  • AJAX(Asynchronous JavaScript And XML): 异步的JavaScript和XML
  • 本身不是新技术, 而是多个技术的综合. 用于快速创建动态网页的技术.
  • 一般的负面如果需要更新内容, 必需重新加载整个页面
  • 而AJAX通过浏览器与服务器进行少量数据交换, 不可以使网页异步更新. 不重新加载整个页面, 对网页部分内容局部更新

原生JavaScript 实现AJAX

  • 核心对象:xMLHttpRequest
    • 用于在后台与服务器交换数据。可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
  • 打开链接:open(method,url,async)
    • method :请求的类型 GET 或 POST.
    • url:请求资源的路径,
    • async:true(异步) 或false(同步)。
  • 发送请求:send(String params)
    • params:请求的参数(POST 专用)。
  • 处理响应:onreadystatechange
    • readyState :0-请求末初始化,1-服务器连接已建立,2-请求已接收 ,3-请求处理中,4-请求已完成,且响应已就绪。
    • status:200-响应已全部OK。
  • 获得响应数据形式
    • response Text :获得字符串形式的响应数据。
    • responseXML:获得XML形式的响应

jQuery的Get方式实现AJAX

  • 核心语法:$.get(url,[data],[callback],[type]);
    • url:请求的资源路径
    • data:发送给服务器端的请求参数,格式可以是key=value,也可以是js对象
    • callback :当请求成功后的回调函数,可以在函数中编写我们的逻辑代码
    • type : 预期的返回数据的类型, 取值可以是xml, html, js, ison, text等
@WebServlet("/userServlet")
public class UserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");

        // 1. 获取请求参数
        String username = req.getParameter("username");

        // 2. 判断姓名是否注册
        if("zhangsan".equals(username)){
            resp.getWriter().write(("<font color='red'>用户名已注册</font>"));
        }else{
            resp.getWriter().write(("<font color='green'>用户名可用</font>"));
        }
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户注册</title>
</head>
<body>
<form autocomplete="off" >
    姓名: <input type="text" id="username">
    <span id="uSpan"></span>
    <br>
    密码: <input type="password" id="password">
    <br>
    <input type="submit" value="注册">
</form>
</body>
<script src="js/jquery-3.6.0.min.js"></script>
<script>
// 1. 为姓名绑定推动焦点事件
    $("#username").blur(function(){
        let username = $("#username").val();
        // 2. jQuery的get方式实现AJAX
        $.get(
        "userServlet",
        "username="+username,
        // 3. 回调函数
        function(data){
            // 将响应的数据显示到span标签
            $("#uSpan").html(data)
        },
        "text"
        );
    })
</script>
</html>

jQuery的POST方式实现AJAX

  • 核心语法:$.post(url,[data],[callback],[type])
    • url:请求的资源路径
    • data:发送给服务器端的请求参数,格式可以是key=value,也可以是js对象
    • callback :当请求成功后的回调函数,可以在函数中编写我们的逻辑代码
    • type : 预期的返回数据的类型, 取值可以是xml, html, js, ison, text等
<script src="js/jquery-3.6.0.min.js"></script>
<script>
// 1. 为姓名绑定推动焦点事件
    $("#username").blur(function(){
        let username = $("#username").val();
        // 2. jQuery的POST方式实现AJAX
        $.post(
        "userServlet",
        "username="+username,
        // 3. 回调函数
        function(data){
            // 将响应的数据显示到span标签
            $("#uSpan").html(data)
        },
        "text"
        );
    })
</script>

jQuery的通用方式实现AJAX

  • 核心语法: $.ajax({name:value,name:value,…});
    • url :请求的资源路径.
    • async :是否异步请求,true-是,false-否(默认是true)。
    • data:发送到服务器的数据,可以是键值对形式,也可以是js对象形式。
    • type:请求方式,POST或GET (默认是GET)。
    • dataType:预期的返回数据的券型,取值可以是xml,html,js, json, text等。
    • success :请求成功时调用的回调函数。
    • error :请求失败时调用的回调函数。
<script src="js/jquery-3.6.0.min.js"></script>
<script>
// 1. 为姓名绑定推动焦点事件
    $("#username").blur(function(){
        let username = $("#username").val();

        $.ajax({
            url: "userServlet",
            async: true,
            data: "username=" + username,
            type: "GET",
            success: function (data) {
                $("#uSpan").html(data)
            },
            dataType: "text",
            error: function () {
                $("#uSpan").html("<font color='red'>出错了, 请稍后重试</font>")
            }
        });
    })
</script>

JSON 格式

类型 语法 说明
对象类型 {name:value,name:value,…} name是字符串类型,
value可以是任意类型
数组/集合类型 [{name:value,…},{name:value,…}] name是字符串类型,
value可以是任意类型
混合类型 {name:
[{name:value,…},{name:value,…}]
}
name是字符串类型,
value可以是任意类型
  • 常用方法
成员方法        说明
stringify(对象) 将指定对象转换为json格式字符串
parse(字符串)   将指定json格式字符串解析成对象
  • JSON Java 转换工具 jackson
类名          说明
ObjectMapper  Jackson工具包的核心类,它提供一些方法来实现JSON字符串和对象之间的转换
TypeReference 对集合泛型的反序列化,使用TypeReference可以明确的指定反序列化的对象类型
  • ObjectMappper 常用方法
方法名                                                 说明
String.writeValueAsString(Object.obj)                  将Java对象转换成JSON字符串
<T>T.readValue(String.json,Class<T>.valueType)         将JSON字符串转换成Java对象
<T>T.readValue(String.json,TypeReference.valueTypeRef) 将JSON字符串转换成Java对象
public class User {
    private String name;
    private Integer age;

    public User(){}
    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}
package com.example.ajax2;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import com.example.ajax2.User;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ObjectMapperTest {

    private ObjectMapper mapper = new ObjectMapper();
    // 1. User对象转换json, json转User对象
    @Test
    public void test01() throws JsonProcessingException {
        User user1 = new User("张三", 23);
        String json = mapper.writeValueAsString(user1);
        System.out.println("json字符串"+json);

        User user2 = mapper.readValue(json, User.class);
        System.out.println("Java对象"+user2);
    }

    // 2.map<String,String>转json json转map<String,String>

    @Test
    public void test02() throws IOException {
        Map<String,String> map = new HashMap<>();
        map.put("姓名","张三");
        map.put("性别","男");
        String json = mapper.writeValueAsString(map);
        System.out.println("json字符串"+json);

        HashMap map2 = mapper.readValue(json, HashMap.class);
        System.out.println("Map对象"+map2);

    }

    // 3. map<String,User>转json json转map<String,User>
    @Test
    public void test03() throws Exception{
        Map<String, User> map1 = new HashMap<>();
        map1.put("1", new User("张三",23));
        map1.put("2", new User("李四",24));

        String json = mapper.writeValueAsString(map1);
        System.out.println("json字符串"+json);

        HashMap map2 = mapper.readValue(json, new TypeReference<HashMap<String, User>>() {} );
        System.out.println("Map对象"+map2);
    }

    // 4.List<String>转json, json转List<String>
    @Test
    public void test04() throws Exception{
        ArrayList<String> list = new ArrayList<>();
        list.add("张三");
        list.add("李四");
        String json = mapper.writeValueAsString(list);
        System.out.println("json字符串"+json);

//        ArrayList<String> list2 = mapper.readVal ue(json, new TypeReference<ArrayList<String>>() { });
        ArrayList<String> list2 = mapper.readValue(json, ArrayList.class);
        System.out.println("List<string>集合"+list2);
     }

    // 5. List<User>转json, json转List<User>
    @Test
    public void test05() throws Exception {
        ArrayList<User> list1 = new ArrayList<>();
        list1.add(new User("张三",23));
        list1.add(new User("李四",24));
        String json = mapper.writeValueAsString(list1);
        System.out.println("json字符串"+json);

        ArrayList<User> list2 = mapper.readValue(json, new TypeReference<ArrayList<User>>() {
        });
        System.out.println("List对象"+list2);
    }
}

搜索联想

package com.lizicai.bean;

public class Student {
    private Integer id;
    private String name;
    private Integer age;

    private Integer score;

    public Student(){}

    public Student(Integer id, String name, Integer age, Integer score) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.score = score;
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>搜索</title>
</head>
<body>
<form autocomplete="off" >
    姓名: <input type="text" id="username" list="userlist" placeholder="输入名称搜索">
    <datalist id="userlist">
    </datalist>
</form>

</body>
<script src="js/jquery-3.6.0.min.js"></script>
<script>
    // 1. 为用户名输入框绑定鼠标点击事件
    $("#username").mousedown(function(){
        // 2. 获取用户名是否为空
        let username = $("#username").val();

        if( username == null || username == ""){
            return;
        }else{
            $.ajax({
                url: "userServlet",
                async: true,
                data: {"username":username},
                type: "POST",
                success: function (data) {
                    let names = "";
                    console.log(data)
                    for(let i=0;i<data.length;i++){
                        names +="<option>"+data[i].name+"</option>";
                        console.log(data[i])
                    }
                    $("#userlist").html(names)
                },
                dataType: "json"
            });
        }

    })
</script>
</html>
package com.lizicai.sql;

import org.apache.ibatis.jdbc.SQL;

public class ReturnSql {
    public String getSelectLikeName(){
        return new SQL(){
            {
                SELECT("*");
                FROM("student");
                WHERE("name like CONCAT('%',#{name},'%')");
                ORDER_BY("score DESC");
                LIMIT("0,4");
            }
        }.toString();
    }
}
package com.lizicai.mapper;

import com.lizicai.bean.Student;
import com.lizicai.sql.ReturnSql;
import org.apache.ibatis.annotations.*;

import java.util.List;

public interface StudentMapper {
    @SelectProvider(type = ReturnSql.class, method = "getSelectAll")
    public abstract List<Student> selectAll();

    @SelectProvider(type = ReturnSql.class, method = "getSelectLikeName")
    public abstract List<Student> selectLikeName(String name);
}
package com.lizicai.service;

import com.lizicai.bean.Student;
import com.lizicai.mapper.StudentMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class Test001 {
    @Test
    public  List<Student> selectLikeName(String name) throws IOException {
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        List<Student> students = mapper.selectLikeName(name);

        for (Student stu : students) {
            System.out.println(stu);
        }

        sqlSession.close();

        is.close();
        return students;
    }
}
package com.lizicai.controller;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.lizicai.bean.Student;
import com.lizicai.service.Test001;

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;

@WebServlet("/userServlet")
public class UserServlet extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


        req.setCharacterEncoding("UTF-8");
        String username = req.getParameter("username");
        ObjectMapper mapper = new ObjectMapper();
        Test001 t = new Test001();
        List<Student> list =  t.selectLikeName(username);
        String json = mapper.writeValueAsString(list);

        resp.setContentType("application/json; charset=utf-8");
        PrintWriter pw = resp.getWriter();
        pw.write(json);
        pw.close();
    }
}

瀑布流分页

create database db11;
use db11;
CREATE TABLE news(
  id INT PRIMARY KEY AUTO_INCREMENT,
  title VARCHAR(999)
);

DELIMITER $$
CREATE PROCEDURE create_date()
BEGIN
    DECLARE i INT;
    SET i=1;
    WHILE i<=100 do
        INSERT INTO news VALUES (NULL,CONCAT('今天吃瓜啦,瓜',i));
        SET i=i+1;
        end WHILE;
end $$

CALL create_date();
  • 如何确定当前显示的数据已经浏览完毕
    • 公式: 滚动条距询问的距离+滚去条上下滚动的距离+当前窗口的高度>=100
    • 当前文档高度: 存储10条数据,100px
    • 滚去条距询问的距离: 1px
    • 当前窗口的高度: 80px
    • 滚去条上下滚去的距离: >=19px
  • 前置知识
功能                  说明
$(function(){})       页面加载事件
$(window)             获取当前窗口对象
scroll()              鼠标滚去事件
$(window).height()    当前窗口的高度
$(window).scrollTop() 滚去条上下滚去的距离
$(document).height()  当前文档的高度
package com.lizicai.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.Page;
import com.lizicai.bean.News;
import com.lizicai.service.NewsService;
import com.lizicai.service.impl.NewsServiceImpl;

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;

@WebServlet("/newsList")
public class NewsServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        String pageNum = req.getParameter("pageNum");
        String pageSize = req.getParameter("pageSize");

        System.out.println(pageNum+" "+pageSize+"----");

        Integer intPageNum = Integer.parseInt(pageNum) ;
        Integer intPageSize = Integer.parseInt(pageSize) ;

        ObjectMapper mapper = new ObjectMapper();
        NewsService newsService = new NewsServiceImpl();
        Page<News> page = newsService.pageQuery(intPageNum,intPageSize);

        String json = mapper.writeValueAsString(page);

        resp.setContentType("application/json; charset=utf-8");
        PrintWriter pw = resp.getWriter();
        pw.write(json);
        pw.close();
    }
}
package com.lizicai.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import com.lizicai.bean.News;
import com.lizicai.service.NewsService;
import com.lizicai.service.impl.NewsServiceImpl;

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;

@WebServlet("/newsList2")
public class NewsServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        String pageNum = req.getParameter("pageNum");
        String pageSize = req.getParameter("pageSize");

        System.out.println(pageNum+" "+pageSize+"----");

        Integer intPageNum = Integer.parseInt(pageNum) ;
        Integer intPageSize = Integer.parseInt(pageSize) ;

        ObjectMapper mapper = new ObjectMapper();
        NewsService newsService = new NewsServiceImpl();
        Page page = newsService.pageQuery(intPageNum,intPageSize);

        PageInfo<List<News>> pageInfo = new PageInfo<>(page);

        String json = mapper.writeValueAsString(pageInfo);

        resp.setContentType("application/json; charset=utf-8");
        PrintWriter pw = resp.getWriter();
        pw.write(json);
        pw.close();
    }
}
<script>
    //1.定义发送请求标记
    let send = true;

    //2.定义当前页码和每页显示的条数
    let pageNum = 1;
    let pageSize = 10;

    //3.定义滚动条距底部的距离
    let bottom = 1

    //4.设置页面加载事件
    $(function (){
        //5.为当前窗口绑定滚动条滚动事件
        $(window).scroll(function (){
            //6.获取必要信息,用于计算当前展示数据是否浏览完毕

            //当前窗口的高度
            let windowHeight = $(window).height() ;
            //当前滚动条从上往下滚动的距离
            let scrollTop = $(window).scrollTop();
            //当前文档的高度
            let docHeight = $(document).height() ;

            //7.计算当前展示数据什么时候浏览完毕
            //当 滚动条距底部的距离 + 当前滚动条滚动的距离 + 当前窗口的高度 >= 当前文档的高度
            if((bottom + scrollTop + windowHeight) >= docHeight) {
                //8.判断请求标记是否为true
                if(send == true){
                    // 如果当前页大于10,则将加载动图隐藏并结束方法

                    //9.将请求标记置为false,当前异步操作完成前,不能重新发起请求
                    send = false;
                    //10.根据当前页和每页显示的条数来 请求查询分页数据
                    queryByPage(pageNum, pageSize);
                    //11.当前页码+1
                    pageNum++;
                }
            }
        });
    })

    //请求查询分页数据的函数
    function queryByPage(pageNum, pageSize){
        //将加载动图显示
        $(".loading").show();

        //发起AJAX异步请求
        $.ajax({
            url:"newsList",
            data:{"pageNum":pageNum,"pageSize":pageSize},
            type:"POST",
            dataType:"json",
            success:function (data){
                if(data.length == 0){
                    // 加载动图隐藏
                    $(".loading").hide();
                    $("#no").html("我也是有底线的")
                    return;
                }

                // 将数据进行显示
                let titles = "";
                for(let i=0;i<data.length;i++){
                     titles += "<li>\n" +
                         "                <div class=\"title-box\">\n" +
                         "                    <a href=\"#\" class=\"link\">\n" +
                                            data[i].title+
                         "                        <hr>\n" +
                         "                    </a>\n" +
                         "                </div>\n" +
                         "            </li>";
                }
                //追加到页面
                $(".news_list").append(titles);

                //将请求标记置为true
                send = true;
            }
        })
    }
</script>
<script>
    // 1. 定义当前页码和每页显示的条数
    let pageNum = 1;
    let pageSize = 10;

    // 2. 调用查询数据的方法
    queryByPage(pageNum, pageSize)

    // 3. 定义请求查询分布数据的函数, 发起AJAX异步请求, 将数据显示到页面
    function queryByPage(pageNum, pageSize){
         $.ajax({
            url:"newsList2",
            data:{"pageNum":pageNum,"pageSize":pageSize},
            type:"POST",
            dataType:"json",
            success:function (pageInfo){
                let titles = "";
                for( let i=0;i<pageInfo.list.length;i++){
                    titles +=  "<li>\n" +
                         "                <div class=\"title-box\">\n" +
                         "                    <a href=\"#\" class=\"link\">\n" +
                                            pageInfo.list[i].title+
                         "                        <hr>\n" +
                         "                    </a>\n" +
                         "                </div>\n" +
                         "            </li>";
                }
                // 将数据显示到页面上
                $(".news_list").html(titles);

                 // 4. 为分布按钮区域设置页数参数(总页数和当前页)
                 $("#light-pagination").pagination({
                     pages:pageInfo.pages,
                     currentPage: pageInfo.pageNum
                 });

                 // 5. 为分布按钮绑定单击事件, 完成上一页下一页
                $(".page-link").click(function(){
                    // 获取点击按钮的文本内容
                     let page = $(this).html()
                    console.log(page)
                    // 如果点击的是Prev, 调用查询方法, 查询当前页的上一页数据
                    if( page == "Prev"){
                        queryByPage(pageInfo.pageNum-1, pageSize)
                    } else if(page == "Next"){
                       queryByPage(pageInfo.pageNum+1, pageSize)
                    } else{
                       queryByPage(page, pageSize)
                    }
                })
            }
         })
    }
</script>