首页 > WEB开发 > 后台开发 > 数据库分页(MySQL)
2014
08-27

数据库分页(MySQL)

03. 数据库分页13

在《MySQL(SQL入门)》一文中介绍过数据库的基本查询语句(单表查询),在《MySQL(JDBC)》一文中介绍过多表查询技术,本文是DQL的补充。当查询的结果集过多时,不应一次请求查询所有结果,而是采用数据库分页技术,每次查询部分结果集并显示。

1、分页查询语句

不同数据库的分页查询语句是不同的,MySQL中的分页查询语句为:

select * from 表名 limit M,N;

M:开始记录的索引(第一条记录的索引为0)N:一次查询几条记录。

所以从Customers表中分页查询的语句为:

第一页:select * from customers limit 0,10;

第二页:select * from customers limit 10,10;

……

第n页:select * from customers limit (n-1)*10,10;

本文以Customers数据库为例,主要实现下图所示的两种分页效果。Customers表下载

03. 数据库分页463

2、第一种分页的实现

1)设计一个Page类(核心),封装所有与分页有关的数据。

分析第一节的分页效果图片,可知展示一页需要的数据有:

  • 每页展示记录条数(pageSize):预先设定
  • 一页记录本身(records):从数据库中查找时需要向Dao层提供开始记录的索引(startIndex)以及查询条数(pageSize)
  • 当前页码(currentPageNum)、总页数(totalPageNum)、上页页码(prePageNum)、下页页码(nextPageNum):总页数要需根据数据库中查询总结果条数(totalRecordsNum)计算。

这些数据的关系如下图所示,箭头表示依赖关系,如查找records时,需要startIndex。(没有列出pageSize,因为pageSize需要自己预先指定)

03. 数据库分页820

由上图可以看出,实例化一个Page类时,需要传入currentPageNum和totalRecordsNum,其他数据都可以计算出来。

package org.flyne.common;

public class Page {
	//每页显示条数(预先定义)
	private int pageSize = 10;
	//页面上显示的记录
	private List records;
	//与页面有关
	private int currentPageNum;
	private int totalPageNum;
	private int prePageNum;
	private int nextPageNum;

	//与数据库有关
	private int totalRecordsNum;
	private int startIndex;

	//实例一个页面时,需要拿到当前页码和总记录条数
	public Page(int currentPageNum,int totalRecordsNum){
		this.currentPageNum = currentPageNum;
		this.totalRecordsNum = totalRecordsNum;
		//计算totalPageNum
		totalPageNum = totalRecordsNum%pageSize==0?totalRecordsNum/pageSize:(totalRecordsNum/pageSize+1);
		//计算startIndex
		startIndex = (currentPageNum - 1)*pageSize;
	}

…………………………各种setter、getter方法…………………………
……………getPrePageNum、getNextPageNum返回前需要计算…………

	public int getPrePageNum() {
		prePageNum = currentPageNum - 1;
		if(prePageNum < 1){
			prePageNum = 1;
		}
		return prePageNum;
	}
	public int getNextPageNum() {
		nextPageNum = currentPageNum + 1;
		if(nextPageNum > totalPageNum){
			nextPageNum = totalPageNum;
		}
		return nextPageNum;
	}
}

2)在service层加入findOneCustomerPage方法

public class CustomerServiceImpl implements CustomerService {
	private CustomerDao dao = new CustomerDaoImpl();
	public Page findOneCustomerPage(String currentPageNum) {
		int num = 1;//没有指定页码,默认查询第一页
		if(currentPageNum!=null && "".equals(currentPageNum.trim())){
			num = Integer.parseInt(currentPageNum);
		}
		int totalRecordsNums = dao.getTotalRecordsNum();

		//创建Page对象
		Page page = new Page(num,totalRecordsNums);
		page.setRecords(dao.findByPage(page.getStartIndex(),page.getPageSize()));
		return page;
	}
}

3)在DAO层int getTotalRecordsNum、List findByPage方法,略。

4)Servlet中的相关代码:

private void showCustomersList(HttpServletRequest request,
		HttpServletResponse response) throws ServletException, IOException {
	String pageNum = request.getParameter("pageNum");
	Page page = service.findOneCustomerPage(pageNum);
	request.setAttribute("page", page);
	request.getRequestDispatcher("/customerlist.jsp").forward(request, response);
}

5)customerlist.jsp分页相关代码:

<!-- 分页开始 -->
第${page.currentPageNum }页/共${page.totalPageNum }页&nbsp;&nbsp;
<a href="${pageContext.request.contextPath }/servlet/CustomerController?op=showCustomersList&pageNum=1">首页</a>&nbsp;
<c:if test="${page.currentPageNum>1 }">
<a href="${pageContext.request.contextPath }/servlet/CustomerController?op=showCustomersList&pageNum=${page.prePageNum}">上一页</a>&nbsp;
</c:if>

<c:if test="${page.currentPageNum<page.totalPageNum }">
<a href="${pageContext.request.contextPath }/servlet/CustomerController?op=showCustomersList&pageNum=${page.nextPageNum}">下一页</a>&nbsp;
</c:if>
<a href="${pageContext.request.contextPath }/servlet/CustomerController?op=showCustomersList&pageNum=${page.totalPageNum}">尾页</a>&nbsp;&nbsp;

<input type='text' id='pageNum' size=1 />
<input type='button' value="跳转" onclick="jumpTo()"/>
<!-- 分页结束 -->

<script type="text/javascript">
	function jumpTo(){
		var num = document.getElementById("pageNum").value;
		if(/^[1-9][0-9]*$/.test(num)){
			if(num>=1 && num<${page.totalPageNum}){
				window.location.href = "${pageContext.request.contextPath }/servlet/CustomerController?op=showCustomersList&pageNum="+num;
			}else{
				alert("页码超过范围了");
			}
		}
	}
</script>

3、第二种分页的实现

1)改造Page类

在Page类中加入两个字段,表示起始页码和结束页码:

//类似1 2 3 4 5 6 7 8 9的页码
private int startPageNum;
private int endPageNum;

在Page类的构造方法中计算startPageNum、endPageNum,如下:

//计算startPageNum、endPageNum
if(totalPageNum > 9){
	startPageNum = currentPageNum - 4;
	endPageNum = currentPageNum + 4;

	if(startPageNum<1){
		startPageNum = 1;
		endPageNum = 9;
	}
	if(endPageNum > totalPageNum ){
		endPageNum = totalPageNum;
		startPageNum = endPageNum - 8;
	}
}else{
	//没有9页
	startPageNum =1;
	endPageNum = totalPageNum;
}

2)Service、Dao、Servlet中代码不变

3)在customerlist.jsp上一页、下一页之间加入如下代码即可:

<c:forEach begin="${page.startPageNum}" end="${page.endPageNum}" var="pageNum">
	<c:if test="${pageNum==page.currentPageNum}">
		${pageNum}
	</c:if>
	<c:if test="${pageNum!=page.currentPageNum}">
		<a href="${pageContext.request.contextPath }/servlet/CustomerController?op=showCustomersList&pageNum=${pageNum}">${pageNum}</a>
	</c:if>
</c:forEach>

4、抽取customerlist.jsp中的分页代码

如果很多网页都需要用到分页,就可以考虑将customerlist.jsp中的分页代码抽取出来放入common/page.jsp,在需要分页的地方静态引入即可。

1) 改造Page类

增加一个url字段,用于存放分页需要请求的Servlet,并生成其getter和setter方法即可。

// 抽取分页
private String url;

2) Service、Dao层代码不变

3) Servlet中代码微调如下(同第2节中的Servlet):

Page page = service.findPageRecords(num);
// page.url有具体Servlet赋值
page.setUrl("/servlet/CustomerController?op=showCustomersList");
request.setAttribute("page", page);

4)抽取/common/page.jsp页面

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!-- 分页开始 -->
第${page.currentPageNum }页/共${page.totalPageNum }页&nbsp;&nbsp;
<a href="${pageContext.request.contextPath }${page.url}&pageNum=1">首页</a>&nbsp;
<c:if test="${page.currentPageNum>1 }">
	<a href="${pageContext.request.contextPath }${page.url}&pageNum=${page.prePageNum}">上一页</a>&nbsp;
</c:if>

<c:forEach begin="${page.startPageNum}" end="${page.endPageNum}" var="pageNum">
	<c:if test="${pageNum==page.currentPageNum}">
		${pageNum}
	</c:if>
	<c:if test="${pageNum!=page.currentPageNum}">
		<a href="${pageContext.request.contextPath }${page.url}&pageNum=${pageNum}">${pageNum}</a>
	</c:if>
</c:forEach>

<c:if test="${page.currentPageNum<page.totalPageNum }">
	<a href="${pageContext.request.contextPath }${page.url}&pageNum=${page.nextPageNum}">下一页</a>&nbsp;
</c:if>
<a href="${pageContext.request.contextPath }${page.url}&pageNum=${page.totalPageNum}">尾页</a>&nbsp;&nbsp;

<input type='text' id='pageNum' size=1 />
<input type='button' value="跳转" onclick="jumpTo()" />
<!-- 分页结束 -->

5)在customerlist.jsp中静态引入/common/page.jsp

<%@ include file="/common/page.jsp" %>

留下一个回复

你的email不会被公开。