网页分页功能讲解及相关代码模块实现

1.分页的种类

分页有两种,分别是物理分页逻辑分页
物理分页:是指多次去数据库查询,然后返回给前端显示。 物理分页依赖的是某一物理实体,这个物理实体就是数据库,比如MySQL数据库提供了limit关键字,程序员只需要编写带有limit关键字的SQL语句,数据库返回的就是分页结果。
逻辑分页:是指一次讲结果全部查询出来,然后去进行分割显示。逻辑分页依赖的是程序员编写的代码。数据库返回的不是分页结果,而是全部数据,然后再由程序员通过代码获取分页数据,常用的操作是一次性从数据库中查询出全部数据并存储到List集合中,因为List集合有序,再根据索引获取指定范围的数据。
为了使自己更好的理解分页功能,希望读者先看由我自己编写的分页功能实现,再看分页插件 - PageHelper的使用

2.我们采用分页插件 - PageHelper

开发环境结构:idea、maven、SSM框架
1.导入相关maven依赖

 <!--分页插件-->
    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.1.10</version>
    </dependency>

2.我们知道该插件是由mybatis提供的,那么使用其插件肯定要去mybatis配置文件中进行配置

<!--mybatis分页插件pagehelper-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>

3.项目编写实现
在这里插入图片描述
当我们点击了商品管理后,跳转到controller中,然后进行分页返回到前端页面呈现
在这里插入图片描述
现在我们来看相关代码实现
controller相关代码我们看到里面有关于关键字的一些参数,这是因为我还想实现按关键字查询分页功能,于是下面的controller出现了与keyword相关的代码,如果读者不想使用按关键字查询分页的话,只需要将其去掉。

    //商品管理用mybatis插件分页
    @GetMapping("/productManage")
    public String ProductsList(Model model, HttpServletRequest request)
    {
        //接收搜索的关键字
        String keyword = request.getParameter("keywords");
        int pageNum = 1;//当前页数,第一次进入
        String cp = request.getParameter("pageNum"); //获取用户指定的页
        if(cp != null)
        {
            pageNum = Integer.parseInt(cp);
        }                                           //pageSize为每一页显示几条数据,keyword为用户是否搜索查找
        PageInfo pageInfo = productsService.findPage(pageNum,5,keyword);
        //将keyword传入前端,方便下一次页面切换查找
        if(keyword != null) {
            model.addAttribute("searchParams", "&keywords="+keyword);
        }
        model.addAttribute("pageInfo",pageInfo);
        return "admin/admin_product";
    }

service相关代码
1.接口

//带有条件的分页功能
    PageInfo findPage(int page, int pageSize,String keyword);

2.实现类

@Override
    public PageInfo findPage(int page, int pageSize ,String keyword) {
        //需要注意Service层PageHelper.startPage(xxx,yyy);语句后一定是紧跟查询语句
        PageHelper.startPage(page,pageSize);//启动
        //查询所有产品
        List<Products> list=productsMapper.selectAllProducts(keyword);
        PageInfo pageInfo = new PageInfo(list);
        return pageInfo;
    }

我们可以看到上面的controller与service我们都在使用PageInfo,那么他到底是什么呀?我们点击进去一探究竟
Mybatis分页插件 - PageHelper-PageInfo类(这是插件自带的类),我们可以发现他其实就是给我们封装好了分页功能的实现,里面有很多参数,以及ger、set、构造、toString方法和一些边界计算方法等,具体的大家可以去看他的源码。http://git.oschina.net/free/Mybatis_PageHelper,下面的代码是只是该类的一些属性,省略了其他代码

@SuppressWarnings({"rawtypes", "unchecked"})
public class PageInfo<T> extends PageSerializable<T> {
    //当前页
    private int pageNum;
    //每页的数量
    private int pageSize;
    //当前页的数量
    private int size;
    
    //由于startRow和endRow不常用,这里说个具体的用法
    //可以在页面中"显示startRow到endRow 共size条数据"

    //当前页面第一个元素在数据库中的行号
    private int startRow;
    //当前页面最后一个元素在数据库中的行号
    private int endRow;
    //总页数
    private int pages;

    //前一页
    private int prePage;
    //下一页
    private int nextPage;

    //是否为第一页
    private boolean isFirstPage = false;
    //是否为最后一页
    private boolean isLastPage = false;
    //是否有前一页
    private boolean hasPreviousPage = false;
    //是否有下一页
    private boolean hasNextPage = false;
    //导航页码数
    private int navigatePages;
    //所有导航页号
    private int[] navigatepageNums;
    //导航条上的第一页
    private int navigateFirstPage;
    //导航条上的最后一页
    private int navigateLastPage;

Mapper接口

//查询所有产品
    List<Products> selectAllProducts(String keyword);

Mapper映射

<!--查询所有商品-->
    <select id="selectAllProducts"  resultType="products">
        select * from products
        <where>
            <if test=" keyword != null">
                pro_name like concat(concat('%',#{keyword}),'%') and
            </if>
            1 = 1
        </where>
    </select>

为什么说该插件是物理分页呀,我们可以进行一探究竟。修改service实现类的代码

@Override
    public PageInfo findPage(int page, int pageSize ,String keyword) {
        //需要注意Service层PageHelper.startPage(xxx,yyy);语句后一定是紧跟查询语句
        PageHelper.startPage(page,pageSize); //启动
        //查询所有产品
        List<Products> list=productsMapper.selectAllProducts(keyword);
        System.out.println("list为"+list);
        PageInfo pageInfo = new PageInfo(list);
        System.out.println("pageInfo为"+pageInfo);
        return pageInfo;
    }

通过调用该功能,我们在控制台打印出list与pageInfo的结果为在这里插入图片描述
我们可以看到或者理解为他去进行查询的时候,一共进行了两次。第一次首先把全部的数目查出来返回给page,然后再去查第二次,得到当前页面所需要的数据,同时我们能够看到他封装了很多的参数,这些参数就是在前面所提到的PageInfo类的属性

前端jsp页面相关代码

<!---按关键字查询分页->
<form action="${pageContext.request.contextPath}/productManage" method="get">
                    <table class="search-tab">
                        <tr>
                            <th width="120">关键字:</th>
                            <td><input class="common-text" placeholder="关键字(利用商品名称来搜索)" name="keywords" value="${param.keywords }" id="" type="text"></td>
                            <td><input class="btn btn-primary btn2" name="sub" value="查询" type="submit"></td>
                        </tr>
                   </table>
</form>

<form action="#" method="post">
                <div class="result-title">
                    <div class="result-list">
                        <a href="${pageContext.request.contextPath}/gotoAddProductPage"><i class="icon-font"></i>新增商品</a>
                    </div>
                </div>

                <div class="result-content">
                    <table class="result-tab" width="70%">
                        <tr>
                            <th>ID</th>
                            <th>商品名称</th>
                            <th>商品价格</th>
                            <th>商品库存</th>
                            <th>操作</th>
                        </tr>
                        <c:forEach var = "p" items = "${pageInfo.list}">
                            <tr>
                                <td>${p.pro_id }</td>
                                <td><img src="${p.pro_imgurl}" width="60px" height="70px">
                                        ${p.pro_name}
                                </td>
                                <td> ${p.pro_price}</td>
                                <td> ${p.pro_num}</td>
                                <td>
                                </td>
                            </tr>
                        </c:forEach>
                    </table>
                    <div class="list-page">
                        共${pageInfo.total}条记录,当前${pageInfo.pageNum}/${pageInfo.pages }页
                        <a href = "/productManage?pageNum=1${searchParams}">首页</a>
                        <a href = "/productManage?pageNum=${pageInfo.hasPreviousPage?pageInfo.prePage:1}${searchParams}">上一页</a>
                        <a href = "/productManage?pageNum=${pageInfo.hasNextPage?pageInfo.nextPage:pageInfo.pages}${searchParams}">下一页</a>
                        <a href = "/productManage?pageNum=${pageInfo.pages}${searchParams}">尾页</a>
                    </div>
                </div>
            </form>

在这里插入图片描述
其中我要说明的是,在使用EL表达式的时候,items取值不是p a g e I n f o 而 是 {pageInfo}而是pageInfo{pageInfo.list},因为我们的结果集在list里面

按关键字查询分页效果图
在这里插入图片描述

3.我们自己编写分页功能

在这里插入图片描述
进入controller

//用户管理_显示用户列表,并以分页形式显示,我们采用物理分页,即多次去数据库查询记录,然后返回到我们的视图层
    //首先我们需要1.获得用户记录的条数,2.根据条件限制去查找该页的记录
    //另外我们这里也用到了一个模糊查询,进行用户的筛选
    @GetMapping("/userManage")
    public ModelAndView userList(HttpServletRequest request) {
        ModelAndView modelandview = new ModelAndView();

        //接收用户搜索的关键字
        String keyword = request.getParameter("keywords");

        int cpage = 1;//当前页数,第一次进入
        String cp = request.getParameter("cp"); //获取用户指定的页
        if(cp != null)
        {
            cpage = Integer.parseInt(cp);
        }
        //先根据条件获取用户数量
        int arr[] = adminService.totalCountUser(keyword);

        //根据上面返回的结果查询相关的用户
        List<User> userlist = adminService.selectAlluser(cpage,keyword);

        modelandview.addObject("userlist", userlist);
        modelandview.addObject("tsum", arr[0]); //记录总数
        modelandview.addObject("tpage", arr[1]);  //记录总页数
        modelandview.addObject("cpage", cpage);  //当前在第几页

        //保障,进行关键字查询时,在点击下一页的按钮时,也能够将关键字传入,继续上一次之后的查询
        //http://localhost:8080/userManage?keywords=admin&sub=%E6%9F%A5%E8%AF%A2
        //如果不加的下面的if代码的话点击下一页得到的路径就是:http://localhost:8080/userManage?cp=1
        //不会有keywords=xxxx,不能进行模糊查询
        if(keyword != null) {
            modelandview.addObject("searchParams", "&keywords="+keyword);
        }
        modelandview.setViewName("admin/admin_user");
        return modelandview;
    }

service
接口

//根据条件查询所有用户记录
    List<User> selectAlluser(int cpage,String keyword);

实现类

@Override
    public List<User> selectAlluser(int cpage,String keyword) {
        int pagecount = 5;//每页显示条数
        int limit1 =(cpage - 1)*pagecount;
        int limit2 = pagecount;
        Map<String,Object> map = new HashMap<>();
        map.put("keyword",keyword);
        map.put("limit1",limit1);
        map.put("limit2",limit2);
        return adminMapper.selectAlluser(map);
    }

mapper接口

//根据条件查询所有用户记录
    List<User> selectAlluser(Map map);

mapper映射

<!--根据条件查询用户记录-->
    <select id="selectAlluser" parameterType="map" resultType="user">
        select * from user
        <where>
            <if test=" keyword != null">
                username like concat(concat('%',#{keyword}),'%') and
            </if>
            1 = 1
            order by registTime desc limit #{limit1}, #{limit2}
        </where>
    </select>

实现效果图
在这里插入图片描述
关键字查询
在这里插入图片描述


版权声明:本文为qq_45780016原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。