首先,在很多地方都可以用到分页查询,软件开发最基本的增、删、改、查里面的“查”,查询所有用户需要分页,查询相关业务信息需要分页。
分页查询分为下面两种方式:
在sql查询时,先从数据库检索出所有数据的结果集,然后在程序内,通过逻辑语句获得分页需要的的数据。
例如: 检索11-20条userList.subList(10,20);
在sql查询时,从数据库只检索分页需要的数据。通常不同的数据库有着不同的物理分页语句,mysql物理分页,采用limit关键字。
例如:检索11-20条 select *from user limit 10,10 ;(limit m,n 是mysql的语法)
下面介绍的分页查询就是以mysql为例进行说明的。
select * from tablelimit m,n; 其中m是指记录开始的index(从0开始表示第一条记录),n是指从第m+1条开始,取n条。
好了,这是mysql数据库中sql语句的分页原理。下面看具体实施。
在这里我用的是最基础的servlet来实现控制层与视图层进行交互,在各大框架中原理也是类似,更简单。
我们现在要做一个客户管理系统,前端页面需要返回客户基本信息。比如:
假设我们现在不用分页的话,在后台控制器里面我们需要返回一个List
List
request.setAttribute("list", list);
request.getRequestDispatcher("/list.jsp").forward(request,response);
我们只需要给页面返回一个Cust实体类的集合list,然后在页面进行遍历就可以拿到所有的客户信息。这样的话只有一个Cust实体类已经足够,因为我们要的仅仅只是Cust的一个集合。
然后业务层,DAO层你只需稍微处理一下就可以了,比如DAO层的SQL应该只需这样写就可以了:"select * fromcustomer ";
好了,因为客户信息太多了(几百条、几万条甚至更多),我们又不想用逻辑分页,我们应该做一下几个步骤。
l 第一步,你要从前端获取当前需要显示的页(第几页)和每页的记录数。
l 第二步,调用业务层(service)中分页查询的方法。
l 第三步,存入request带到前端页面(jsp)。
l 代码如下所示:
//1、获取当前要显示的页和每页记录数
int thisPage = Integer.parseInt(request.getParameter("thisPage"));
int pageSize = Integer.parseInt(request.getParameter("pageSize"));
//2、调用service中分页查询客户的方法
List list = custService.findCustPage(thisPage, pageSize);
####首先,说明一点,这里只返回一个Cust的List是不够的,先放在这里,等下再修改这里的代码,这样更易于理解###
//3、存入request带到我们的jsp页面中
request.setAttribute("list", list);
request.getRequestDispatcher("/pageList.jsp").forward(request, response);
*思考问题*
接下来,我们思考一个问题,我们首页需要显示数据的详细信息之外(也就是一个实体类的集合需要展示在页面上的信息),还需要显示什么信息呢?我们是不是还需要显示下面这个:
共XXX条记录共XX页首页上一页 1 2 3 4 5 下一页尾页
那我们后端控制层只返回一个Cust的List够不够?显然是不够的,这样我们在service层分页查询客户信息方法处理的时候就需要注意了:
我们是不是需要bean类来封装一些信息,以便于放入request域在前端显示,比如:bean里卖年封装一个List
因为现在只处理一个实体类Cust,这个bean没有用泛型写成通用的bean,应该是要写成通用的pageBean的,不过在这里为了方便讲清楚分页的原理暂时不涉及泛型:
import java.util.List;
public class CustPage {
/**
* 当前页码
*/
private int thisPage;
/**
* 每页大小
*/
private int pageSize;
/**
* 总记录数
*/
private long allRow;
/**
* 总页
*/
private int totalPage;
/**
* 首页
*/
private int firstPage;
/**
* 尾页
*/
private int lastPage;
/**
* 上一页
*/
private int previousPage;
/**
* 下一页
*/
private int nextPage;
/**
* 返回的Custs列表
*/
private List list;
public CustPage() {
}
public CustPage(int thisPage, int pageSize, long allRow, int totalPage, int firstPage, int lastPage,
int previousPage, int nextPage, List list) {
super();
this.thisPage = thisPage;
this.pageSize = pageSize;
this.allRow = allRow;
this.totalPage = totalPage;
this.firstPage = firstPage;
this.lastPage = lastPage;
this.previousPage = previousPage;
this.nextPage = nextPage;
this.list = list;
}
public int getThisPage() {
return thisPage;
}
public void setThisPage(int thisPage) {
this.thisPage = thisPage;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public long getAllRow() {
return allRow;
}
public void setAllRow(long allRow) {
this.allRow = allRow;
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public int getFirstPage() {
return firstPage;
}
public void setFirstPage(int firstPage) {
this.firstPage = firstPage;
}
public int getLastPage() {
return lastPage;
}
public void setLastPage(int lastPage) {
this.lastPage = lastPage;
}
public int getPreviousPage() {
return previousPage;
}
public void setPreviousPage(int previousPage) {
this.previousPage = previousPage;
}
public int getNextPage() {
return nextPage;
}
public void setNextPage(int nextPage) {
this.nextPage = nextPage;
}
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
}
我们需要在业务层处理所有的业务,将上面CustPage这个bean里面我们需要在前端显示的信息装进去。代码如下:
@Override
public CustPage findCustPage(int thisPage, int pageSize) {
CustPage custPage = new CustPage();
//设置当前页
custPage.setThisPage(thisPage);
//设置每页大小
custPage.setPageSize(pageSize);
//查找总记录数,设置总记录数
long allRow = custDao.getAllRow();
custPage.setAllRow(allRow);
//计算总页数并设置
int totalPage = (int) (allRow/pageSize+(allRow%pageSize==0?0:1));
custPage.setTotalPage(totalPage);
//设置首页
custPage.setFirstPage(1);
//设置尾页
custPage.setLastPage(totalPage);
//设置上一个
custPage.setPreviousPage(thisPage==1?1:thisPage-1);
//设置下一页
custPage.setNextPage(thisPage==totalPage?totalPage:thisPage+1);
//获得需要分页的实体类数据
List list = custDao.getCustByPage((thisPage-1)*pageSize,pageSize);
custPage.setList(list);
return custPage;
}
我在这里使用了阿帕奇的一个jdbc工具,DBUtils。是一个非常轻量,非常好用的DAO层JDBC工具,现在的Hibernate太庞大了。有兴趣的朋友可以查看我其他博文进行了解。
@Override
public long getAllRow() {
String sql = "select count(*) from customer";
try{
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
return (Long)runner.query(sql, new ScalarHandler());
}catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
}
@Override
public List getCustByPage(int thisPage, int pageSize) {
String sql = "select * from customer limit ?,?";
try{
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
return runner.query(sql, new BeanListHandler(Cust.class), thisPage,pageSize);
}catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
}
好了,到这里,大概已经清楚了分页的原理,具体运用到项目中,还是需要自己实践。