通用分页的详细讲解看这一篇就够了(内含源码)(上)

简介: 通用分页的详细讲解看这一篇就够了(内含源码)

一、为什么要使用通用分页以及使用场景

1.为什么使用通用分页

            在软件或者网站上,数据量是庞大的,不可能一下把全部的数据给你展示出来,因为渲染需要时间而且很耗内存,如果使用分页,每次就会处理一小块的数据,大大的提升了我们的性能以及用户体验度。但是在开发中不单单只是一个模块需要分页,有很多地方都需要分页,这时候我们就可以将重复的代码进行优化,变成——通用分页供开发人员使用。

2.使用场景

1.大型程序的执行:

大型程序需要占用大量的内存空间,但是内存空间是有限的,使用分页技术可以将程序的数据、代码、堆和栈等分为多个页面,只有需要时才将页面加载到内存中。

2.并发运行多个程序:

操作系统可以同时运行多个程序,分页技术可以让操作系统将内存中的每个程序区分开,保护每个程序的独立性和安全性。

3.身份验证和访问权限管理:

身份验证和访问权限管理需要划分内存空间,每个用户所占用的内存空间应该是独立的,这样才能有效地实现权限管理。

4.网络服务器:

作为网络服务器,需要同时处理多个客户端的请求,而每个客户端所占用的内存空间也是独立的,使用分页技术可以让操作系统为每个客户端分配独立的内存空间,保护服务器的稳定性和安全性。

5.计算机游戏:

计算机游戏通常具有图形和音效等较复杂的特性,需要占用大量的内存空间。使用分页技术可以提高游戏的运行速度和稳定性。

3.以往分页的实现及代码

往常都是这么写分页方法的,先封装一个分页工具类保存页码、一页的条目、总记录数以及是否分页,然后当成参数传递到Dao层的分页方法中,再将需要查询的关键词或是类别传递即可,下面看一下代码!!

分页工具类

package com.xw.util;
/**
 * 分页工具类
 *
 */
public class PageBean {
  private int page = 1;// 页码
  private int rows = 10;// 页大小
  private int total = 0;// 总记录数
  private boolean pagination = true;// 是否分页
  public PageBean() {
    super();
  }
  public int getPage() {
    return page;
  }
  public void setPage(int page) {
    this.page = page;
  }
  public int getRows() {
    return rows;
  }
  public void setRows(int rows) {
    this.rows = rows;
  }
  public int getTotal() {
    return total;
  }
  public void setTotal(int total) {
    this.total = total;
  }
  public void setTotal(String total) {
    this.total = Integer.parseInt(total);
  }
  public boolean isPagination() {
    return pagination;
  }
  public void setPagination(boolean pagination) {
    this.pagination = pagination;
  }
  /**
   * 获得起始记录的下标
   * 
   * @return
   */
  public int getStartIndex() {
    return (this.page - 1) * this.rows;
  }
  @Override
  public String toString() {
    return "PageBean [page=" + page + ", rows=" + rows + ", total=" + total + ", pagination=" + pagination + "]";
  }
}

Dao层分页方法

/**以往分页
   * @param b 关键词
   * @param p 分页工具类
   * @return 根据条件查询出来的数据
   */
  public List<Book> list(Book b, PageBean p) {
    // 获取连接对象
    Connection conn = null;// 连接对象
    PreparedStatement ps = null;// 执行对象
    ResultSet rs = null;// 结果集对象
    List<Book> list = new ArrayList<Book>();// 集合实体
    Book book = null;// 实体对象
    try {
      // 加载驱动
      conn = DBAccess.getConnection();
      // 编写sql语句
      String sql = "SELECT * FROM t_mvc_book where 1=1 ";
      // 当关键词不为空的时候,拼接模糊查询的sql语句
      String bname = b.getBname();
      if (StringUtils.isNotBlank(bname)) {
        sql += "  and bname like '%" + bname + "%'";
        //判断是否分页
        if(p!=null && p.isPagination()) {
          sql+="  LIMIT "+p.getStartIndex()+","+p.getRows();
        }
      }
      // 执行sql语句
      ps = conn.prepareStatement(sql);
      // 返回结果集
      rs = ps.executeQuery();
      // 遍历结果集
      while (rs.next()) {
        // 将结果集加入实体
        book = new Book(rs.getInt(1), rs.getString(2), rs.getFloat(3));
        // 将实体加入list集合
        list.add(book);
      }
    } catch (Exception e) {
      // 捕捉异常
      e.printStackTrace();
    } finally {
      // 关闭资源
      DBAccess.close(conn);
      DBAccess.close(rs);
      DBAccess.close(ps);
    }
    // 返回结果
    return list;
  }

打印结果

虽然我们的功能实现了,但是我们要对另一个模块的时候很多重复的代码还需要在写一次,是不是非常的麻烦,这时候我们的通用分页就上场了!!!

二、通用分页的讲解

0.前言

博主这里用的数据库是mysql,如果还不会mysql安装的话可以点击mysql安装教程,下面我以Book实体为例,开展我的通用分页查询讲解

package com.xw.entity;
/**book实体类
 * @author Java方文山
 *
 */
public class Book {
  private int bid;
  private String bname;
  private float price;
  public Book() {
    // TODO Auto-generated constructor stub
  }
  public Book(int bid, String bname, float price) {
    super();
    this.bid = bid;
    this.bname = bname;
    this.price = price;
  }
  @Override
  public String toString() {
    return "Book [bid=" + bid + ", bname=" + bname + ", price=" + price + "]";
  }
  public int getBid() {
    return bid;
  }
  public void setBid(int bid) {
    this.bid = bid;
  }
  public String getBname() {
    return bname;
  }
  public void setBname(String bname) {
    this.bname = bname;
  }
  public float getPrice() {
    return price;
  }
  public void setPrice(float price) {
    this.price = price;
  }
}

1.实现通用分页步骤分析

看完以上的代码,你想到的是怎么优化呢?

我来给大家分享一下我的优化方式,首先所有分页代码都大同小异,只有sql语句和遍历结果集的区域代码不一致,所以我们只需要将这里稍加改动,就可以变成我们的通用分页。首先我们通用的basedao里面要判断是否分页,因为有些模块不需要分页,如果不需要分页的话就进行“原sql”查询即可,需要分页,就将模糊查询的总记录数计算出来以及回显最终展示的数据即可。其次就是遍历结果集的时候,因为我们不知道将来传递进来的是什么对象,所以可以用到反射的机制,动态的获取属性。

2.实现通用分页

①编写BaseDao(通用分页)

package com.xw.dao;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.xw.entity.Book;
import com.xw.util.DBAccess;
import com.xw.util.PageBean;
import com.xw.util.StringUtils;
/**封装通用分页
 * @author Java方文山
 *
 */
public class BaseDao<T> {
  /**封装通用的分页方法
   * @param cl 需要分页的实体
   * @param sql sql语句
   * @param p 封装的分页工具类
   * @return 按照条件查询的结果
   */
  public List<T> executeQuery(Class cl,String sql,PageBean p) throws Exception{
    //获取连接对象
    Connection conn=null;//连接对象
    PreparedStatement ps=null;//执行对象
    ResultSet rs=null;//结果集对象
    List<T> list=new ArrayList<T>();//集合
    //判断是否分页
    if(p!=null && p.isPagination()) {
      //总记录数
      String count=getSQLcount(sql);
      conn=DBAccess.getConnection();
      ps=conn.prepareStatement(count);
      rs=ps.executeQuery();
      //将总记录数赋值给分页工具类
      if(rs.next()) {
        p.setTotal(rs.getObject("n").toString());
      }
      //初始下标(第几条开始)
      String pagesize=getSQpagesize(sql,p);
      conn=DBAccess.getConnection();
      ps=conn.prepareStatement(pagesize);
      rs=ps.executeQuery();
    }else {
      //加载驱动
      conn=DBAccess.getConnection();
      //执行sql语句
      ps=conn.prepareStatement(sql);
      //返回结果集
      rs=ps.executeQuery();
    }
    try {
      //遍历结果集
      while(rs.next()) {
        //创建类的实例
        T T=(T) cl.newInstance();
        //拿到传递进来的实体所有属性
        Field[] declaredFields = cl.getDeclaredFields();
        //遍历属性
        for (Field field : declaredFields) {
          //打开访问权限
          field.setAccessible(true);
          //等价于b.setBid(rs.getInt("bid"),设置T实例的属性
          field.set(T, rs.getObject(field.getName()));
        }
        //将实体添加到集合
        list.add(T);
      }
    } catch (Exception e) {
      //捕捉异常
      e.printStackTrace();
    }finally {
      //关闭资源
      DBAccess.close(conn);
      DBAccess.close(rs);
      DBAccess.close(ps);
    }
    //返回结果
    return list;
  }
  /**计算最终展示数据的sql
   * @param sql 传递过来的sql语句
   * @param p 分页工具类
   * @return 
   */
  private String getSQpagesize(String sql, PageBean p) {
    return sql+"  LIMIT "+p.getStartIndex()+","+p.getRows();
  }
  /**查看总记录数
   * @param sql 传递过来的sql语句
   * @return 数量
   */
  private String getSQLcount(String sql) {
    return "SELECT COUNT(1) as n from("+sql+") t";
  }
}

②BookDao层继承BaseDao

package com.xw.dao;
import static org.junit.Assert.fail;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.xw.entity.Book;
import com.xw.util.DBAccess;
import com.xw.util.PageBean;
import com.xw.util.StringUtils;
/**
 * book的dao类
 * 
 * @author Java方文山
 *
 */
public class BookDao extends BaseDao<Book> {
  public List<Book> BaseDaoTest(Book b, PageBean p) throws Exception {
    // 编写sql语句
    String sql = "SELECT * FROM t_mvc_book where 1=1 ";
    // 当关键词不为空的时候,拼接模糊查询的sql语句
    String bname = b.getBname();
    if (StringUtils.isNotBlank(bname)) {
      sql += "  and bname like '%" + bname + "%'";
    }
    //调用basedao封装的方法
    return executeQuery(b.getClass(), sql, p);
  }
  @Test
  public void test2() throws Exception {
    System.out.println("通用分页");
    //调用BookDao
    BookDao bookDao = new BookDao();
    //模拟关键词
    Book b = new Book();
    b.setBname("圣墟");
    //调用分页工具类
    PageBean p = new PageBean();
    //记录查询记录数
    int count = 0;
        //允许分页
    p.setPagination(true);
    List<Book> list = bookDao.BaseDaoTest(b, p);
    for (Book book : list) {
      System.out.println(book);
      count++;
    }
    System.out.println("总记录数目: " + count);
  }
}

打印结果:

至此,我们的通用分页就写完了,我们将来只需要写sql语句和参数传递即可,是不是很方便!!

相关文章
|
7月前
|
机器学习/深度学习 编译器 C++
C++模板元模板实战书籍讲解第一章(顺序、分支与循环代码的编写)--前篇
C++模板元模板实战书籍讲解第一章(顺序、分支与循环代码的编写)--前篇
37 0
|
19天前
|
NoSQL 安全 API
【Redi设计与实现】第二章:简单动态字符串
【Redi设计与实现】第二章:简单动态字符串
|
6月前
|
vr&ar 开发工具 iOS开发
visionOS空间计算实战开发教程Day 1:环境安装和编写第一个程序
截至目前visionOS还未在Xcode稳定版中开放,所以需要下载Xcode Beta版。比如我们可以下载Xcode 15.1 beta 2,注意Xcode 15要求系统的版本是macOS Ventura 13.5或更新,也就是说2017年的MacBook Pro基本可以勉强一战,基本上还是推荐使用M系列芯片的电脑进行开发。
92 0
|
8月前
|
缓存 前端开发 关系型数据库
如何实现通用分页(来看我这一篇就够了超级详细内含源码!!!)
如何实现通用分页(来看我这一篇就够了超级详细内含源码!!!)
60 0
|
7月前
|
前端开发 Java UED
通用分页【上】之前端代码
通用分页【上】之前端代码
23 0
|
7月前
|
安全 算法 5G
了解 5G 安全标准,看这一篇就够了
了解 5G 安全标准,看这一篇就够了
176 0
|
9月前
|
SQL Java 关系型数据库
通用分页的详细讲解看这一篇就够了(内含源码)(下)
通用分页的详细讲解看这一篇就够了(内含源码)(下)
56 0
|
9月前
|
Java 数据处理 计算机视觉
自定义通用分页标签一行代码完成分页效果(内含源码)(下)
自定义通用分页标签一行代码完成分页效果(内含源码)(下)
27 0
|
9月前
|
SQL 存储 数据库连接
自定义通用分页标签一行代码完成分页效果(内含源码)(上)
自定义通用分页标签一行代码完成分页效果(内含源码)
26 0
|
10月前
|
存储 数据可视化 Ubuntu
bcftools学习笔记丨软件简介、安装方式、使用方法、核心功能、参数解释等一文速览
bcftools学习笔记丨软件简介、安装方式、使用方法、核心功能、参数解释等一文速览