第四十天:Ajax(js和jquery实现Ajax+java中json转换)

1. 概述(了解)

1.1同步与异步概念

相关知识复习 (对于今天来说,不重要):

阻塞:在能开始做某件事件之前一直等着什么都不做,直到轮到你了就开始做要做的这件事情。

**同步:**自己亲自出马做这个事情

**异步:**让小弟帮你去做事情,做完了给反馈。

同步不一定阻塞。

  • 同步阻塞(BIO)。排队等吃饭,在轮到我之前,我什么都不做,一直盯着门口直到有位子可以坐下来吃饭。
  • 同步非阻塞(NIO)。排队等吃饭,不想干等着,就去逛街,但是每个1分钟回来看下有没有轮到自己。(轮询)
  • 只要是同步,必须是自己亲自做 – 亲自排队。

异步肯定非阻塞。

  • 异步非阻塞(AIO):排队吃饭,在微信公众号上叫个号(相当于留了个微信),然后去逛街,到号了微信上直接通知你有位子了去吃饭。
  • 异步不需要自己亲自做,不用自己亲自排队,安排了微信公众号这个小弟帮你排队。

B/S结构中的同步和异步:

同步请求:浏览器在解析到网页代码某一行时,该行发起了一个请求;在服务器响应该请求前,浏览器什么都不能做,必须得等到请求完成返回数据之后,才会执行后续的代码;这期间浏览器处于假死状态

异步请求:浏览器在解析到网页代码某一行时发起请求后,浏览器可以继续执行后面的代码,继续做其他任何事情,而不用等待服务器响应。会有回调函数接收服务器响应数据并解析渲染。异步请求并不会影响页面的加载与用户的操作,相当于是在两条线上,各走各的,互不影响。

1597542593061

AJAX中的异步请求和局部刷新

AJAX:Asynchronous JavaScript and XML,异步的JavaScriptxml。现在应该叫(AJAJ)。

异步请求:用户对客户端的操作和服务器之间是异步非阻塞的。

局部刷新:把服务器响应的数据放在网页的某一区域刷新展示,而不会造成整个页面刷新。

体验好:不需要刷新整个页面,就不会有闪那一下;

效率高:因为可以只更新N条数据中的一条。

AJAX 不是新的编程语言,而是一种使用现有技术的新的用法。

2. 原生JS实现AJAX(了解)

知道原生JS操作的核心对象:XMLHTTPRequest。代码如下:

regist1.html

<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>
    //1.为姓名绑定失去焦点事件
    document.getElementById("username").onblur = function() {
        //2.创建XMLHttpRequest核心对象
        let xmlHttp = new XMLHttpRequest();

        let username = document.getElementById("username").value;


        //3.打开链接
        /*
            参数1:请求方式
            参数2:请求的URL + 参数
            参数3:是否异步
         */
        xmlHttp.open("GET","userServlet?username="+username,true);
        //xmlHttp.open("GET","userServlet?username="+username,false);

        //5.设置监听,监听到变化了(响应了)之后就开始处理响应
        xmlHttp.onreadystatechange = function() {
            //判断请求和响应是否成功
            if(xmlHttp.readyState == 4 && xmlHttp.status == 200) {
                //将响应的数据显示到span标签
                document.getElementById("uSpan").innerHTML = xmlHttp.responseText;
            }
        };

        //4.发送请求
        xmlHttp.send();

    }
</script>

UserServlet.java

@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");

        //模拟服务器处理请求需要5秒钟
        /*try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/

        //2.判断姓名是否已注册
        // TODO 查询数据库库查询用户名是否可用
        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);
    }
}
API 讲解

20201213102042281

3. jQuery实现AJAX

3.1 $.get()(重点)

格式:

$.get(url,[请求参数],[回调函数],[响应数据格式]);

演示代码:regist2.html

<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.3.1.min.js"></script>
<script>
    //1.为用户名绑定失去焦点事件
    $("#username").blur(function () {
        let username = $("#username").val();

        //2.jQuery的GET方式实现AJAX
        /*
            第一个参数   请求路径
            第二个参数   请求的参数
                支持json      {key:value}
                支持键值对     key=value  ,get请求时,可以直接拼在请求地址后面
            第三个参数   回调函数
                用来处理服务器响应的数据的函数
                形参data      接收服务器响应的数据,名字任意
            第四个参数   type  浏览器以何种形式解析服务器的响应数据
                text/不设置    浏览器以普通文本字符串的形式解析使用响应数据
                json          浏览器以json的形式解析使用响应数据,解析成js对象
                xml           浏览器以xml的形式解析使用响应数据,解析成document对象
         */
    	// $.ajaxSettings.Xxxx=yyy;
        $.get(
            //请求的资源路径
            "userServlet",
            //请求参数
            "username=" + username,
            //回调函数
            function (xxxx) {
                //将响应的数据显示到span标签
                $("#uSpan").html(xxxx);
            },
            //响应数据形式
            "text"
        );
    });
</script>

UserServlet.java

// 同2. 原生js实现ajax(了解)中代码一致

3.2 $.post()(重点)

格式:

$.post(url,[请求参数],[回调函数],[响应数据格式]);

演示代码:regist3.html

<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.3.1.min.js"></script>
<script>
    //1.为用户名绑定失去焦点事件
    $("#username").blur(function () {
        let username = $("#username").val();
        // let username = document.getElementById("username").value;
        // 2.jQuery的POST方式实现AJAX
        /*
            和get方式请求的区别:
                1. 使用方法是$.post
                2. 请求资源路径后不能跟请求参数,请求参数只能放在post方法第二个参数位置
            其他没有任何区别

         */
        /*
            如果想在post请求或者get请求的时候指定更多参数
            可以在$.post/$.get发起请求之前,通过$.ajaxSettings.xxx设置更多参数
        */
        // $.ajaxSettings.Xxxx=yyy;
        $.post(
            //请求的资源路径
            "userServlet",
            //请求参数
            "username=" + username,
            //回调函数
            function (data) {
                //将响应的数据显示到span标签
                $("#uSpan").html(data);
            },
            //响应数据形式
            "text"
        );
    });
</script>

UserServlet.java

// 同2. 原生js实现ajax(了解)中代码一致

3.3 $.ajax({json串})(了解)

/*
$.ajax({key:value,...});  // 所有参数通过json格式传递
​        url:请求的资源路径。
​        async:是否异步请求,true-是,false-否(默认是true)。
​        data:发送到服务器的数据,可以是键值对形式,也可以是js对象形式。
​        type:请求方式,POST或GET(默认是GET)。
​        dataType:返回数据的类型,取值可以是xml,html,js,json,text等,告诉浏览器以该格式解析。
​        success:请求成功时调用的回调函数,后跟匿名函数对象。
​        error:请求失败时调用的回调函数,后跟匿名函数对象。

	书写麻烦,不推荐使用。
*/
/*
`$.get()`和`$.post()`同样可以实现。
只需要在调用这两个方法前,通过`$.ajaxSettings.xxx= yyyy`设置即可;
*/
<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.3.1.min.js"></script>
<script>
    //1.为用户名绑定失去焦点事件
    $("#username").blur(function () {
        let username = $("#username").val();
        //2.jQuery的通用方式实现AJAX
        $.ajax({
            //请求资源路径
            url:"userServletxxx",
            //是否异步
            async:true,
            //请求参数
            data:"username="+username,
            //请求方式
            type:"POST",
            //数据形式
            dataType:"text",
            //请求成功后调用的回调函数
            success:function (data) {
                //将响应的数据显示到span标签
                $("#uSpan").html(data);
            },
            //请求失败后调用的回调函数
            error:function () {
                alert("操作失败...");
            }
        });
    });
</script>

UserServlet.java

// 同2. 原生js实现ajax(了解)中代码一致

4. Json格式转换

4.1 Json概念

Json是一种轻量级的数据交换格式。

轻量级:相对于XML来说,Json本身就是一串字符串,数据量小且生成和解析简单。

数据交换格式:客户端和服务器传递数据的格式。

Json组成规则:

  1. 由键值对组成,由{}包裹;
  2. 键和值都用""包裹,键值之间使用:拼接,多个键值对之间使用,分割;键的双引号可以省略不写;
  3. key可以为字符串,value可以为数字、字符串、布尔、数组、json对象、json对象数组。

分类:

  1. Json对象:{"key1":"value1", "key2":"value2"}
  2. Json数组:[{"key1":"value1","key2":"value2"},{"key3":"value3","key4":"value4"}]
  3. 复杂Json{"k1":"v1","k2":[{"k21":"v21","k22":"v22"},{"k3":"v3","k4":"v4"}]}

使用:

  1. 前端中,Json中有两种形式

    • Json对象的形式存在,我们称之为Json对象(本质是一个js对象)。当我们需要使用Json中数据的时候,可以通过json对象.key获取对应的值;
    • Json格式的字符串形式存在,我们称之为Json字符串。当我们需要在前端需要和后台交换数据的时候,会把Json对象转成Json字符串;
    • 两种形式可以使用JSON类完成转换。stringify(json对象)转成strparse(str)解析json对象。

    前后台交换数据,一般都是通过字符串作为载体。所以说,如果要把某个json对象的内容传递到后台,一般先要把它转成json格式的字符串,然后再发送。

  2. 后台中,Json是以字符串形式存在

    • 后台中数据传递的载体是Model对象,前后台数据交换格式是json

    • 后台会做对象(model/list/map)和Json字符串之间的转换;

    • 手动转换:获取java对象的属性和对应的值,手动按照json要求的格式拼接成json字符串;手动切割Json字符串,然后设置到对象中;

    • 自动转换:使用第三方的工具类,完成java对象和json字符串的相互转换。

4.2 常见Json转换工具

两个概念

  • 序列化:java对象转换到Json字符串
  • 反序列化:Json字符串转换到java对象

常见工具(Json解析库)及特点

  • Jackson: 序列化效率最高,SpringMVC底层默认使用
  • fastjson:阿里巴巴公司开源,反序列化效率最高,移动端诸如Android使用较多
  • gson:谷歌公司开源,对复杂json支持最好,稳定;国内使用不多

4.3 序列化:JavaBean对象转Json字符串(重点)

// 导包,三个
// jackson-annotations-2.2.3.jar
// jackson-core-2.2.3.jar
// jackson-databind-2.2.3.jar

// 核心对象
OjbectMapper om = new ObjectMapper();

// 常用的是序列化,解析请求的时候是反序列化,不存在json格式字符串
// 转换成字符串
String jsonStr = om.writeValueAsString(bean/list/map);
// 转换成字符串并写入输出流/文件,可以配合respone使用(response.getWriter()/getOutputStream())
om.writeValue(File/response.outputStream()/response.getWriter(),bean/list/map);

4.4 反序列化:Json字符串转JavaBean(了解)

// 导包,三个
// jackson-annotations-2.2.3.jar
// jackson-core-2.2.3.jar
// jackson-databind-2.2.3.jar

// 核心对象
OjbectMapper om = new ObjectMapper();

// 反序列化不常用
// 如果是普通类型 bean/普通list/map
T t = om.readValue(jsonStr,T.class);
// 如果泛型是自定义类型(弃用),也可以直接使用上述方式:返回值类型.class
//T t = om.readValue(jsonStr, new TypeReference<T>(){});

4.5 案例演示

/*
    JSON转换工具的使用
 */
public class ObjectMapperTest {
    private ObjectMapper mapper = new ObjectMapper();
    /*
        1.User对象转json, json转User对象
          json字符串 = {"name":"张三","age":23}
          user对象 = User{name='张三', age=23}
     */
    @Test
    public void test01() throws Exception{
        //User对象转json字符串 序列化
        // writeValueAsString bean对象转成字符串
        // writeValue           bean对象转成字符串之后再写入到某个位置(文件、输出流)
        User user = new User("张三",23);
        String json = mapper.writeValueAsString(user);
        System.out.println("json字符串:" + json);

        //json转User对象 反序列化 readValue
        User user2 = mapper.readValue(json, User.class);
        System.out.println("java对象:" + user2);
    }

    /*
         2.map<String,String>转json, json转map<String,String>
          json字符串 = {"姓名":"张三","性别":"男"}
          map对象 = {姓名=张三, 性别=男}
     */
    @Test
    public void test02() throws Exception{
        //map<String,String>转json
        HashMap<String,String> map = new HashMap<>();
        map.put("姓名","张三");
        map.put("性别","男");
        String json = mapper.writeValueAsString(map);
        System.out.println("json字符串:" + json);

        //json转map<String,String>
        HashMap<String,String> map2 = mapper.readValue(json, HashMap.class);
        System.out.println("java对象:" + map2);
    }

    /*
        3.map<String,User>转json, json转map<String,User>
          json字符串 = {"一班":{"name":"张三","age":23},"二班":{"name":"李四","age":24}}
          map对象 = {一班=User{name='张三', age=23}, 二班=User{name='李四', age=24}}
     */
    @Test
    public void test03() throws Exception{
        //map<String,User>转json
        HashMap<String,User> map = new HashMap<>();
        map.put("一班",new User("张三",23));
        map.put("二班",new User("李四",24));
        String json = mapper.writeValueAsString(map);
        System.out.println("json字符串:" + json);

        // 不需要new TypeReference的匿名内部类了,直接使用反序列化的目标对象类型的字节码对象即可
        //HashMap<String,User> map2 = mapper.readValue(json,new TypeReference<HashMap<String,User>>(){});
        //json转map<String,User>
        HashMap<String,User> map2 = mapper.readValue(json,HashMap.class);
        System.out.println("java对象:" + map2);
    }

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

        //json转 List<String>
        ArrayList<String> list2 = mapper.readValue(json,ArrayList.class);
        System.out.println("java对象:" + list2);
    }

    /*
        5.List<User>转json, json转List<User>
          json字符串 = [{"name":"张三","age":23},{"name":"李四","age":24}]
          list对象 = [User{name='张三', age=23}, User{name='李四', age=24}]
     */
    @Test
    public void test05() throws Exception{
        //List<User>转json
        ArrayList<User> list = new ArrayList<>();
        list.add(new User("张三",23));
        list.add(new User("李四",24));
        String json = mapper.writeValueAsString(list);
        System.out.println("json字符串:" + json);

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

5.综合案例一

优化细节1:修改触发事件

$("#username").keyup(function (e) {/*.....*/}

优化细节2:添加功能

// 选中id为show的div的所有子div元素
    // 鼠标悬停,背景颜色高亮
    /*
        参数1:绑定的事件名称
        参数2:子元素选择器
        参数3:绑定的函数对象
        效果:选择父元素的所有符合参数2的子元素,为其(们)参数1时间绑定参数3函数
     */
    $("#show").on("mouseover","div",function () {
        // 背景色高亮
        // this代表的是某一个子元素对象(js对象)
        $(this).css("background","yellow");
    });

    // 鼠标移除时,还原背景色
    $("#show").on("mouseout","div",function () {
        // 取消背景色高亮
        // this代表的是某一个子元素对象(js对象)
        $(this).css("background","none");
    });


   // 鼠标点击时,获取当前元素的文本内容,添加到搜索框
    $("#show").on("click","div",function () {
        // this代表的是某一个子元素对象(js对象)
        // 获取文本内容
        let keyword = $(this).html();

        // 添加到搜索框
        $("#username").val(keyword);

        // 隐藏联想框
        $("#show").hide();

        // 输入框内容更新后再发起一次查询
        $("#username").keyup();
    });

完整代码

<form autocomplete="off">
    <div class="content">
        <img src="img/logo.jpg">
        <br/><br/>
        <input type="text" id="username">
        <input type="button" value="搜索一下">
        <!--用于显示联想的数据-->
        <div id="show" class="show"></div>
    </div>
</form>
</body>
<script src="js/jquery-3.3.1.min.js"></script>
<script>
    //1.为用户名输入框绑定鼠标点击事件
    // $("#username").mousedown(function () {
    //1.为用户名输入框绑定按键弹起事件
    $("#username").keyup(function () {
        //2.获取输入的用户名
        let username = $("#username").val();

        //3.判断用户名是否为空
        // if(username == null || username == "") {
        if (!username) {
            //4.如果为空,将联想框隐藏
            $("#show").hide();
            return;
        }

        //5.如果不为空,发送AJAX请求。并将数据显示到联想框
        $.ajax({
            //请求的资源路径
            url: "userServlet",
            //请求参数
            data: {"username": username},
            //请求方式
            type: "POST",
            //响应数据形式
            dataType: "json",
            //请求成功后的回调函数,data是一个js数组(本质上是一个集合/数组,因为后台响应的是把集合序列化的字符串)
            success: function (data) {
                //将返回的数据显示到show的div
                // console.log(data);
                let names = "";
                for (let i = 0; i < data.length; i++) {
                    names += "<div>" + data[i].name + "</div>";
                }
                $("#show").html(names);
                $("#show").show();
            }
        });
    });

    // 选中id为show的div的所有子div元素
    // 鼠标悬停,背景颜色高亮
    /*
        参数1:绑定的事件名称
        参数2:子元素选择器
        参数3:绑定的函数对象
        效果:选择父元素的所有符合参数2的子元素,为其(们)参数1时间绑定参数3函数
     */
    $("#show").on("mouseover","div",function () {
        // 背景色高亮
        // this代表的是某一个子元素对象(js对象)
        $(this).css("background","yellow");
    });

    // 鼠标移除时,还原背景色
    $("#show").on("mouseout","div",function () {
        // 取消背景色高亮
        // this代表的是某一个子元素对象(js对象)
        $(this).css("background","none");
    });


   // 鼠标点击时,获取当前元素的文本内容,添加到搜索框
    $("#show").on("click","div",function () {
        // this代表的是某一个子元素对象(js对象)
        // 获取文本内容
        let keyword = $(this).html();

        // 添加到搜索框
        $("#username").val(keyword);

        // 隐藏联想框
        $("#show").hide();

        // 输入框内容更新后再发起一次查询
        $("#username").keyup();
    });

</script>

UserServlet

@WebServlet("/userServlet")
public class UserServlet extends HttpServlet {
    @Override
    protected void doPost(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.调用业务层的模糊查询方法得到数据
        UserService service = new UserServiceImpl();
        List<User> users = service.selectLike(username);

        //3.将数据转成JSON,响应到客户端
        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writeValueAsString(users);
        resp.getWriter().write(json);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }
}

UserSeriveImpl

public class UserServiceImpl implements UserService {
    @Override
    public List<User> selectLike(String username) {
        List<User> users = null;
        SqlSession sqlSession = null;
        InputStream is = null;
        try{
            //1.加载核心配置文件
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            //2.获取SqlSession工厂对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            //3.通过SqlSession工厂对象获取SqlSession对象
            sqlSession = sqlSessionFactory.openSession(true);
            //4.获取UserMapper接口的实现类对象
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            //5.调用实现类对象的模糊查询方法
            users = mapper.selectLike(username);
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            //6.释放资源
            if(sqlSession != null) {
                sqlSession.close();
            }
            if(is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //7.返回结果到控制层
        return users;
    }
}

UserMapper

public interface UserMapper {
    /*
        模糊查询
     */
    @Select("SELECT * FROM user WHERE name LIKE CONCAT('%',#{username},'%') ORDER BY search_count DESC LIMIT 0,4")
    public abstract List<User> selectLike(String username);
}

6.案例二

6.1 瀑布流分页

6.1.1 判断页面滚动

20201213161137966

6.1.2 案例代码

index.html

<script src="js/jquery-3.3.1.min.js"></script>
<script>
    //1.定义发送请求标记。作用:当因为网络等原因造成加载数据过慢时,用户的多次请求不会重复发送,降低服务器压力
    let send = true;

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

    //3.定义滚动条距底部的距离,该值越大,体验约丝滑
    let bottom = 5;

    //4.设置页面加载事件
    $(function () {
        //5.为当前窗口绑定滚动条滚动事件
        $(window).scroll(function () {
            //8.判断请求标记是否为true
            // 把该判断提到该位置,作用是:减少无效的获取各种高度的操作,降低浏览器运行压力
            // if(send == true) {
            if(send) {
                //6.获取必要信息,用于计算当前展示数据是否浏览完毕
                //当前窗口的高度
                let windowHeight = $(window).height();

                //滚动条从上到下滚动距离
                let scrollTop = $(window).scrollTop();

                //当前文档的高度
                let docHeight = $(document).height();

                //7.计算当前展示数据是否浏览完毕
                //当 滚动条距底部的距离 + 当前滚动条滚动的距离 + 当前窗口的高度 >= 当前文档的高度
                if((bottom + scrollTop + windowHeight) >= docHeight) {

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

    //定义查询分页数据的函数
    function queryByPage(start,pageSize){
        //加载动图显示
        $(".loading").show();
        //发起AJAX请求
        $.ajax({
            //请求的资源路径
            url:"newsServlet",
            //请求的参数
            data:{"start":start,"pageSize":pageSize},
            //请求的方式
            type:"POST",
            //响应数据形式
            dataType:"json",
            //请求成功后的回调函数
            success:function (data) {
                if(!data.length) {
                    $(".loading").hide();
                    $("#no").html("我也是有底线的...");
                    return;
                }
                //加载动图隐藏
                $(".loading").hide();
                //将数据显示
                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>

NewsServlet.java

@WebServlet("/newsServlet")
public class NewsServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求和响应的编码
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");

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

        /* 程序健壮性判断
        	1. 防止为提交这两个值
			2. 防止提交的值不符合格式要求
        */
        int startNum = 1;
        int pageSizeNum = 10;

        try {
            startNum = Integer.parseInt(start);

        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            pageSizeNum = Integer.parseInt(pageSize);

        } catch (Exception e) {
            e.printStackTrace();
        }
        /* 程序健壮性判断结束 */

        //2.根据当前页码和每页显示的条数来调用业务层的查询方法,得到分页Page对象
        NewsService service = new NewsServiceImpl();
        Page page = service.pageQuery(startNum, pageSizeNum);


        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        3.将得到的数据转为JSON
        //String json = new ObjectMapper().writeValueAsString(page);
        //
        4.将数据响应给客户端
        //resp.getWriter().write(json);

    	new ObjectMapper().writeValue(resp.getWriter(), page);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
}

6.2 页码分页(练习)

6.2.1 响应数据解析

20201213172656025

6.2.2 页面执行流程重点

页面正文没有内容,但是发起请求后,会将数据填充到正文的ul中。填充时要覆盖html,不要追加append

控件效果不好,以后也不是我们用,理解就可以。

地址栏输入非法内容,建议做健壮性判断


开发人员选项,查看分页按钮是超链接

判断发送请求的参数根据按钮上的文本进行区分。

6.2.3 案例代码

页面主展示区域和分页插件区域

<div class="center">
    <!-- 新闻标题显示区域 -->
    <ul class="news_list">

    </ul>

    <!-- 分页插件区域 -->
    <div class="content">
        <div class="pagination-holder clearfix">
            <div id="light-pagination" class="pagination"></div>
        </div>
    </div>

</div>

页面js代码逻辑

<script src="js/jquery-3.3.1.min.js"></script>
<script src="js/jquery.simplePagination.js"></script>
<script>
    //1.定义当前页码和每页显示的条数
    let start = 1;
    let pageSize = 10;

    //2.调用事件方法,页面加载之后,自动触发一次查询。默认查询第一页的10条
    queryByPage(start,pageSize);

    //3.定义请求查询分页数据的函数,发起AJAX异步请求,将数据显示到页面
    function queryByPage(start,pageSize) {
        $.ajax({
            //请求的资源路径
            url:"newsServlet2",
            //请求的参数
            data:{"start":start,"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.为分页按钮<超链接>绑定单击事件,完成上一页下一页查询功能
                $("#light-pagination .page-link").click(function () {
                    //获取点击按钮的文本内容
                    let page = $(this).html();
                    //如果点击的是Prev,调用查询方法,查询当前页的上一页数据
                    if(page == "Prev") {
                        queryByPage(pageInfo.pageNum - 1,pageSize);
                    }else if (page == "Next") {
                        //如果点击的是Next,调用查询方法,查询当前页的下一页数据
                        queryByPage(pageInfo.pageNum + 1,pageSize);
                    } else {
                        //调用查询方法,查询当前页的数据
                        // 这里直接获取当前页的字符串即可,后台解析成数字使用
                        // 后台建议使用健壮性判断
                        queryByPage(page,pageSize);
                    }
                });
            }
        });
    }

</script>

后台代码逻辑

@WebServlet("/newsServlet2")
public class NewsServlet2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求和响应的编码
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");

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

        // TODO 分页查询参数健壮性判断
        
        //2.根据当前页码和每页显示的条数来调用业务层的查询方法,得到分页Page对象
        NewsService service = new NewsServiceImpl();
        Page page = service.pageQuery(Integer.parseInt(start), Integer.parseInt(pageSize));

        //3.封装PageInfo对象
        PageInfo<List<News>> info = new PageInfo<>(page);

        //4.将得到的数据转为JSON
        String json = new ObjectMapper().writeValueAsString(info);

        //5.将数据响应给客户端
        resp.getWriter().write(json);

    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }
}

6.4 page和pageInfo的区别

Java代码中分别打印page对象、pageInfo对象、page对象jackson序列化后的字符串、pageInfo序列化后的字符串

代码如下(NewsServiceImpl.java中):

//5.封装Page对象   start:当前页码   pageSize:每页显示的条数
page = PageHelper.startPage(start,pageSize);

//6.调用实现类对象的查询全部方法,此时底层执行的就是MySQL的limit分页查询语句
List<News> news = mapper.selectAll();

// 创建pageInfo对象,并序列化成json格式字符串
PageInfo<News> newsPageInfo = new PageInfo<>(news);
// 分别打印page对象和pageInfo对象
System.out.println("page = " + page);
System.out.println("newsPageInfo = " + newsPageInfo);

// 把两个对象通过jackson序列化之后,打印得到的字符串
String pageStr = new ObjectMapper().writeValueAsString(page);
System.out.println("pageStr = " + pageStr);
String pageInfoStr = new ObjectMapper().writeValueAsString(newsPageInfo);
System.out.println("pageInfoStr = " + pageInfoStr);

结果如下:

page = 
Page{count=true, pageNum=1, pageSize=10, startRow=0, endRow=10, total=100, pages=10, reasonable=false, pageSizeZero=false}[com.jzh.bean.News@447c03dd,...,com.jzh.bean.News@3d8fd6a7]

newsPageInfo = 
PageInfo{pageNum=1, pageSize=10, size=10, startRow=1, endRow=10, total=100, pages=10, list=Page{count=true, pageNum=1, pageSize=10, startRow=0, endRow=10, total=100, pages=10, reasonable=false, pageSizeZero=false}[com.jzh.bean.News@447c03dd,...,com.jzh.bean.News@3d8fd6a7], prePage=0, nextPage=2, isFirstPage=true, isLastPage=false, hasPreviousPage=false, hasNextPage=true, navigatePages=8, navigateFirstPage=1, navigateLastPage=8, navigatepageNums=[1, 2, 3, 4, 5, 6, 7, 8]}

pageStr = [{"id":1,"title":"奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”1"},...,{"id":10,"title":"奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”10"}]

pageInfoStr = {"total":100,"list":[{"id":1,"title":"奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”1"},{"id":2,"title":"奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”2"},{"id":3,"title":"奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”3"},{"id":4,"title":"奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”4"},{"id":5,"title":"奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”5"},{"id":6,"title":"奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”6"},{"id":7,"title":"奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”7"},{"id":8,"title":"奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”8"},{"id":9,"title":"奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”9"},{"id":10,"title":"奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”10"}],"pageNum":1,"pageSize":10,"size":10,"startRow":1,"endRow":10,"pages":10,"prePage":0,"nextPage":2,"isFirstPage":true,"isLastPage":false,"hasPreviousPage":false,"hasNextPage":true,"navigatePages":8,"navigatepageNums":[1,2,3,4,5,6,7,8],"navigateFirstPage":1,"navigateLastPage":8}

结论:

jackson在序列化list结合对象时,只会序列化集合容器中内容;

page父类是ArrayList,本质上是一个list集合;jackson在序列化page对象时,就只会序列化存储在其中的多条记录数据,而忽略分页数据。

navigateFirstPage=1, navigateLastPage=8, navigatepageNums=[1, 2, 3, 4, 5, 6, 7, 8]}

pageStr = [{“id”:1,“title”:“奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”1”},…,{“id”:10,“title”:“奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”10”}]

pageInfoStr = {“total”:100,“list”:[{“id”:1,“title”:“奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”1”},{“id”:2,“title”:“奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”2”},{“id”:3,“title”:“奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”3”},{“id”:4,“title”:“奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”4”},{“id”:5,“title”:“奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”5”},{“id”:6,“title”:“奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”6”},{“id”:7,“title”:“奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”7”},{“id”:8,“title”:“奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”8”},{“id”:9,“title”:“奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”9”},{“id”:10,“title”:“奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”10”}],“pageNum”:1,“pageSize”:10,“size”:10,“startRow”:1,“endRow”:10,“pages”:10,“prePage”:0,“nextPage”:2,“isFirstPage”:true,“isLastPage”:false,“hasPreviousPage”:false,“hasNextPage”:true,“navigatePages”:8,“navigatepageNums”:[1,2,3,4,5,6,7,8],“navigateFirstPage”:1,“navigateLastPage”:8}




结论:

> `jackson`在序列化`list`结合对象时,只会序列化集合容器中内容;
>
> `page`父类是`ArrayList`,本质上是一个list集合;`jackson`在序列化`page`对象时,就只会序列化存储在其中的多条记录数据,而忽略分页数据。
>
> `pageInfo`是一个实体类,`jackson`在序列化`pageinfo`对象时,则会正常的序列化多条记录数据和分页数据。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值