一、为什么要使用通用分页以及使用场景
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语句和参数传递即可,是不是很方便!!