基于Spring Mvc 动态分页查询网页的重点部分


声名

提示:这里没有完整的项目流程,只记录了动态查询网页的重点内容。
如何搭建一个完整项目流程:基于 Spring Mvc 一个简单项目的基本流程 <用户注册功能>(校正版)


提示:以下是本篇文章正文内容,下面案例可供参考

一、后端

1. mapper(非重点)

1. 接口文件

定义了方法:

List<UserInfo> findAll();

在这里插入图片描述

2. 映射文件

编写了查询信息的SQL语句:

<select id="findAll" resultType="com.upc.oa.po.UserInfo">
        select userId, userName, userRealName, userSex, userEmail
        from user_info
        where userStatus=1
</select>

在这里插入图片描述

3. 测试(略)

2. 业务逻辑(重点)

上次博客中提到过,业务逻辑存在的必要性即处理数据。这此我们分页查询数据,则从mapper获取的数据,将在业务逻辑中进行分页处理,在反馈给控制器时已经是分页处理后的数据了。

1. 配置PageHelper

在pom.xml文件空白处,右键选择Generate-Dependency-搜索pagehelper-选择pagehelper-spring-boot-starter 1.3.1,效果如下:
在这里插入图片描述

2. 创建接口

使用新的实体类PageInfo作为业务逻辑的返回值类型。这是PageHelper里一种数据类型,将原来的List结构体数据转化为PageInfo实体类后,可自动封装处理List数据,变成分页处理后的结果。在service接口文件中写:

package com.upc.oa.service;

import com.github.pagehelper.PageInfo;
import com.upc.oa.dto.UserinfoDto;
import com.upc.oa.po.UserInfo;

import java.util.List;

public interface UserInfoService {

    // 返回值类型:PageInfo<>
    // 参数是:pageNum页码和pageSize每页显示的总数据条数
    PageInfo<UserInfo> findAll(int pageNum, int pageSize);
}

3. 创建impl

这里需要将mapper查询到的数据,封装为PageInfo类型,然后反馈给控制器

package com.upc.oa.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.upc.oa.dto.UserinfoDto;
import com.upc.oa.mapper.UserinfoMapper;
import com.upc.oa.po.UserInfo;
import com.upc.oa.service.UserInfoService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

// 注解,声名这是业务逻辑
@Service
public class UserInfoServiceImpl implements UserInfoService {
    // 声名要对哪个映射文件进行操作
    @Resource
    private UserinfoMapper userinfoMapper;

    @Override
    public PageInfo<UserInfo> findAll(int pageNum, int pageSize) {

        // 定义PageInfo<>数据类型的变量,封装mapper的查询结果
        PageInfo<UserInfo> page=null;
        
        // 设置显示页:显示页的页码是第pageNum页;显示页显示的条数pageSize条
        PageHelper.startPage(pageNum,pageSize);

        // 获取后端查询数据,保存在user里
        List<UserInfo> users=null;
        users=userinfoMapper.findAll();

        // 将users文件转为PageInfo格式
        // 4:将默认的每页显示8个数据,设置为每页显示4个数据
        page=new PageInfo<>(users,4);
        // pageSize 与 这个 4 的区别:如果没有传入pageSize则默认每页显示4条,反之每页显示pagesize条
        
        // 返回处理后的查询结果
        return page;
    }
}

4. 测试

业务逻辑也是可以测试的。

  1. 创建测试文件,选择要测试的接口
    在这里插入图片描述
  2. 添加注解,编写参数,测试业务逻辑即可
package com.upc.oa.service;

import com.github.pagehelper.PageInfo;
import com.upc.oa.po.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class UserInfoServiceTest {

    @Resource
    private UserInfoService userInfoService;
    @Test
    void findAll() {
        // 编写参数
        int pageNum= 1;
        int pageSize= 3;
        
        // 调用接口函数
        PageInfo<UserInfo> page = userInfoService.findAll(pageNum,pageSize);
        
        // 输出测试结果
        System.out.println(page);

    }
}

3. 控制器(重点)

1. 创建控制器

注意控制器返回的数据类型也是PageInfo

package com.upc.oa.controller;

import com.github.pagehelper.PageInfo;
import com.upc.oa.dto.UserinfoDto;
import com.upc.oa.po.UserInfo;
import com.upc.oa.service.UserInfoService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;


// 配置路径 /user
@RestController
@RequestMapping("/user")
public class UserController {
    // 声名控制器要调用业务逻辑是哪个
    @Resource
    private UserInfoService userInfoService;
   
    // 在 @RestController的声名下,会将我们返回的数据自动转为json格式,可以直接使用
    // 控制器向前端返回的数据:为 PageInfo<UserInfo> 封装的查询结果,
    // 前端向控制器传入的参数为:int pageNum, int pageSize
    @RequestMapping("/findAll")
    public PageInfo<UserInfo> findAll(int pageNum, int pageSize){
        // 调用业务逻辑,将业务逻辑反馈的数据直接返回即可
        return  userInfoService.findAll(pageNum,pageSize);

    }
}

2. 测试控制器

  1. 启动XXXApplicaton
    一定要启动成功,正常运行才可进入后续步骤
  2. 选择Idea自己的插件
    在这里插入图片描述
    界面介绍:
    在这里插入图片描述
  3. 配置界面
    在这里插入图片描述
    在这里插入图片描述
  4. 测试
    在这里插入图片描述

二、前端(重点)

先在static文件夹下,创建users.html文件

1. 配置jQuery、bootstrap

bootstrap: 提供大量的Css样式和少量Js组键。Css中有一种选择器叫类选择器,我们定义类名,然后编写这个类选择器的修饰内容,我们需要修饰谁,就在谁那里添加class=“类名”。而bootStrap是自己定义好了一堆Css的类选择器函数,我们自己直接在控件中添加自己想要的class=""即可进行修饰。
使用方法: 访问官网,使用模板套用即可BootStrap模板

1.1 搭载jquery

在static文件夹下,创建jquery文件夹,将jquery-3.6.0.min.js复制到该文件夹下
在这里插入图片描述

2. 搭载bootstrap

  1. 复制bootstrap文件夹
    在这里插入图片描述
  2. 粘贴到static中,目录结构如下即可
    在这里插入图片描述

3. 配置jQuery、bootstrap

采用拖拽方法将需要的文件直接拖拽到title标签下方空白处,注意拖拽顺序!
在这里插入图片描述
在这里插入图片描述

4. ReBuild 项目

2. 编写Html文件:

1. 触发事件

全选功能为例:

Html部分

 <!--   表头部分   -->
            <thead>
            <tr>
                <!--  全选功能 :点击全选小方框,所有显示数据都被勾选 -->
                <td>
                    <!--  onclik="selectAllCk" :设置触发事件,当选中这个方框时会触发selectAllCk事件,
                                                事件具体内容可以在Script标签中编写;
                          this.checked:若该方框被选中为True,反之为False;
                          事件输入的参数:this.checked,如果该方框被选中则selectAllCk事件的参数为True;
                     -->
                    <input type="checkbox" id="chall" onclick="selectAllCk(this.checked)">
                </td>
                <td>账号</td>
                <td>真实姓名</td>
                <td>性别</td>
                <td>操作</td>
            </tr>
            </thead>

Script部分

<!-- 编写selectAllCk的事件 (传入的参数命名为f)-->
<script>
    function selectAllCk(f){
        //实现全选原理:若全选选框被选中,则传入的参数f为ture,则所有name为ids的选框都变为True被选中
        //找界面中input控件中所有name为ids的控件,并把控件的checked设置为传入的参数f
        jQuery("input[name='ids']").prop("checked",f);

        // 使用name命名数据勾选框的原因:
        // name属性值可以重复,id就是主键不可重复,对于全选功能,使用name属性,可以同时勾选多个name为ids的input
    }
</script>

2. 使用jQuery传递数据/语句

在Script脚本中,反引号中可以编写Html语句,使用jQuery传递到对应控件即可执行

在表体显示数据为例:

Html部分

<!-- 表体部分,具体内容靠script的方法传入 -->
            <tbody id="data">
            </tbody>

Script部分

			// 1.获取查询的数据
            var arrs=rst.list;
            var trs = '';
            // 利用循环+反引号,获取了多少数据,就创建多少条语句
            for (var i=0;i<arrs.length;i++){
                //获取每一行对应的用户对象的信息
                var u=arrs[i];
                // 创建语句
                trs=trs+`
                <tr>
                    <td>
                        <input type="checkbox" name="ids" value="${u.userId}">
                    </td>
                    <td>${u.userName}</td>
                    <td>${u.userRealName}</td>
                    <td>${u.userSex==1?'男':'女'}</td>
                    <td>${u.userEmail}</td>
                    <td>
                        <!--  按钮,采用超链接  -->
                        <a href="#" >删除</a>
                        <a href="#" >编辑</a>
                    </td>
                </tr>
                `;
            }
            // 把处理trs代码字符串添加到Html部分中,id为data的控件中
            jQuery("#data").html(trs)

3. 知识点

1. script与html的数据交互
  1. 在html设置触发事件,html可向脚本传递参数,而事件内容可修改html
  2. 在script,使用jQuery,获取对应id/name的数值
  3. 在script,通过jquery,定位id,可向html传递数据、甚至是html语句
4.完整的Html

完成了分页显示功能,里面html与script交织在一起,实在是没有找到一个好的方法来表示,只能把完整代码和注释放在这了,累了,毁灭吧。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <!--  配置jQuery、bootStrap  -->
    <link rel="stylesheet" href="bootstrap-4.6.0-dist/css/bootstrap.min.css">
    <script src="jquery/jquery-3.6.0.min.js"></script>
    <script src="bootstrap-4.6.0-dist/js/bootstrap.min.js"></script>

    <!--  Css部分,对部分控件进行修饰  -->
    <style type="text/css">
        /*给按钮换个位置,放右边,设置一下据其他控件的距离*/
        #top{
            /**/
            padding: 10px 20px;
            text-align: right;
        }
        /*让两个div控件在一行显示的修饰方法*/
        /*让page_div里的right向右飘*/
        #page_div #right{
            float: right;
        }
        /*让page_div里的left向左飘*/
        #page_div #left{
            float: left;
        }
    </style>

</head>
<body>

<!--整个界面放在该div中-->
<div id="container">

    <!-- 批量删除按钮-->
    <div id="top">
        <button type="button" class="btn btn-danger btn-lg">批量删除</button>
    </div>

    <!--  显示数据的部分  -->
    <div id="bottom">
        <!-- 将整个显示数据的部分设置为一个表格,分为:表头thead、表体tbody、表尾tfoot -->
        <table class="table table-bordered table-hover table-striped">
            <!--   表头部分   -->
            <thead>
            <tr>
                <!--  全选功能 :点击全选小方框,所有显示数据都被勾选 -->
                <td>
                    <!--  onclik="selectAllCk" :设置触发事件,当选中这个方框时会触发selectAllCk事件,
                                                事件具体内容可以在Script标签中编写;
                          this.checked:若该方框被选中为True,反之为False;
                          事件输入的参数:this.checked,如果该方框被选中则selectAllCk事件的参数为True;
                     -->
                    <input type="checkbox" id="chall" onclick="selectAllCk(this.checked)">
                </td>
                <td>账号</td>
                <td>真实姓名</td>
                <td>性别</td>
                <td>操作</td>
            </tr>
            </thead>

            <!-- 表体部分,具体内容靠script的方法传入 -->
            <tbody id="data">
            </tbody>

            <!-- 表尾部分 -->
            <tfoot>
                <tr>
                    <!--  分页显示 colspan=6:即设置一行中单个列宽,这里设置单个列宽为原来的6倍,即一个单元格占六列宽-->
                    <td colspan="6">
                        <div id="page_div">
                            <!-- 左边部分 分页显示情况  -->
                           <div id="left">
                               <!--    span是行内标签,特点是:等于是一行里有多个还不自动换行  -->
                              当前页/总页数: <span id="pageNum"></span> / <span id="pages"></span>&nbsp;&nbsp;&nbsp;&nbsp;总条数=<span id="totals"></span>
                           </div>
                            <!--   右边部分 换页操作   -->
                            <div id="right">
                            </div>
                        </div>
                    </td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
            </tfoot>
        </table>
    </div>
</div>

<!-- 编写selectAllCk的事件 (传入的参数命名为f)-->
<script>
    function selectAllCk(f){
        //实现全选原理:若全选选框被选中,则传入的参数f为ture,则所有name为ids的选框都变为True被选中
        //找界面中input控件中所有name为ids的控件,并把控件的checked设置为传入的参数f
        jQuery("input[name='ids']").prop("checked",f);

        // 使用name命名数据勾选框的原因:
        // name属性值可以重复,id就是主键不可重复,对于全选功能,使用name属性,可以同时勾选多个name为ids的input
    }
</script>

<!--页面加载时,完成获取某一页的数据-->
<script>
    //定义全局变量,存放:当前页码、每页条数、总页数
    var pageNum = 1; // 默认显示第一页
    var pageSize = 3; // 默认每页显示3条
    var pageNums = 0 ; // 默认总页数为 0

    // init():每次调用init方法时,会获取后台数据,重新显示表体、表尾
    function init() {

        // 获取后台数据部分

        var param={
          //控制器参数   定义变量
            "pageNum" : pageNum,
            "pageSize" : pageSize
        };

        //使用jquery访问后端的user/findAll控制器
        // rst 是控制器反馈的查询结果
        jQuery.post("user/findAll",param,function (rst) {

            // 表尾的left:分页情况------------------------------
            // 获取总页数
            pageNums=rst.pages;
            //将pageNums数值传递到id=pages的控件中,下面同理
            jQuery("#pages").html(pageNums);
            jQuery("#pageNum").html(pageNum);
            jQuery("#totals").html(rst.total);
            //--------------------------------------------------

            //表体:显示查询数据----------------------------------
            // 1.获取查询的数据
            var arrs=rst.list;
            var trs = '';
            // 利用循环,我们获取了多少数据,就创建多少行对应语句
            for (var i=0;i<arrs.length;i++){
                //循环一次,在页面中产生一行数据

                //获取每一行对应的用户对象
                var u=arrs[i];

                //使用反引号,作用:定义字符串模板
                trs=trs+`
                <tr>
                    <td>
                        <input type="checkbox" name="ids" value="${u.userId}">
                    </td>
                    <td>${u.userName}</td>
                    <td>${u.userRealName}</td>
                    <td>${u.userSex==1?'男':'女'}</td>
                    <td>${u.userEmail}</td>
                    <td>
                        <!--  按钮,采用超链接  -->
                        <a href="#" >删除</a>
                        <a href="#" >编辑</a>
                    </td>
                </tr>
                `;
            }

            // 把for循环处理好的html代码字符串添加到data表体中去
            jQuery("#data").html(trs)
            //------------------------------------------------------

            //设置表尾right:换页部分--------------------------------

            // 上一页按钮---------
            var nav=`
                    <ul class="pagination">
                        <li class="page-item">
                                                               <!--  设置触发事件,当点击上一页,触发pageUtil事件,传入要前往的页(当前页的上一页) -->
                            <a href="#" class="page-link" οnclick="pageUtil(${pageNum-1})">上一页</a>
                        </li>
            `;

            //循环设置页码,以及激活页码-------------
            //rst.navigatepageNums:是个数组,例如:若是1~4页,则数组是[1,2,3,4]
            var nums=rst.navigatepageNums;
            for(var i=0;i<nums.length;i++)
            {
                nav+=`                                 <!-- 如果当前页与页码数组中的某一页相等则,激活当前页  -->
                        <li class="page-item"   ${pageNum==nums[i]?'active':''}>
                              <a href="#" class="page-link">${nums[i]}</a>
                        </li>
                `;
            }

            // 下一页按钮----------------
            nav=nav+`
                        <li class="page-item">
                                                            <!--  设置触发事件,当点击下一页,触发pageUtil事件,传入要前往的页(当前页的下一页) -->
                              <a href="#" class="page-link" οnclick="pageUtil(${pageNum+1})">下一页</a>
                        </li>

                    </ul>
            `;

            // 将换页设置传到right控件
            jQuery("#right").html(nav);
        })
    }

    //页面加载完毕后,重新执行init方法,此时若用户选择了新的页码,则刷新数据,反之数据还是原来数据,只是又获取了一次
    jQuery(function () {
        init();
    })

</script>

<!--编写pageUtil事件-->
<script>
    //完成换页操作
    function pageUtil(num) {
        //修改pageNum为num,即要前往的页
        pageNum=num;
        // 如果进入当前页小于1就保持第一页
        if(num<=1)
        {
            pageNum=1;
        }
        // 如果进入当前页大于,总页数就直显示最后一页
        if(num>pageNums){
            pageNum=pageNums;
        }
        // 用户每次修改页码后,我们重新调用init()函数,即可重新显示对应页的数据(pageNum是个public属性,可以直接调用、修改)
        init();
    }
</script>
</body>
</html>

最终效果,除了删除功能没有实现,其他都是实现了,等我功力深了,再来填坑。
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值