1、课程名称:分页算法
真分页、假分页、分页组件
2、知识点
2.1、上次课程的主要知识点
1、 问题总结
2.2、本次预计讲解的知识点
1、 分页算法的用处
2、 分页算法的实现:真分页、加分页
3、 将分页代码形成组件
3、具体内容
3.1、问题的引出
例如:现在要查询雇员表中的全部数据
<%@ page contentType="text/html;charset=GBK"%>
<%@ page import="java.sql.*"%>
<%--
查询出EMP表中的全部数据
--%>
<%!
public static final String DBDRIVER = "oracle.jdbc.driver.OracleDriver" ;
public static final String DBURL = "jdbc:oracle:thin:@localhost:1521:MLDN" ;
public static final String DBUSER = "scott" ;
public static final String DBPASS = "tiger" ;
%>
<%
Connection conn = null ;
PreparedStatement pstmt = null ;
ResultSet rs = null ;
%>
<%
try{
%>
<%
Class.forName(DBDRIVER) ;
conn = DriverManager.getConnection(DBURL,DBUSER,DBPASS) ;
String sql = "SELECT empno,ename,job,sal,comm,hiredate FROM emp" ;
pstmt = conn.prepareStatement(sql) ;
rs = pstmt.executeQuery() ;
%>
<center>
<table border="1" width="80%">
<tr>
<td>雇员编号</td>
<td>雇员姓名</td>
<td>雇员工作</td>
<td>雇员工资</td>
<td>雇员佣金</td>
<td>雇佣日期</td>
</tr>
<%
while(rs.next()){
int empno = rs.getInt(1) ;
String ename = rs.getString(2) ;
String job = rs.getString(3) ;
float sal = rs.getFloat(4) ;
float comm = rs.getFloat(5) ;
java.util.Date date = rs.getDate(6) ;
%>
<tr>
<td><%=empno%></td>
<td><%=ename%></td>
<td><%=job%></td>
<td><%=sal%></td>
<td><%=comm%></td>
<td><%=date%></td>
</tr>
<%
}
%>
</table>
</center>
<%
}catch(Exception e){
// 向tomcat中进行打印
System.out.println(e) ;
}finally{
%>
<%
rs.close() ;
pstmt.close() ;
conn.close() ;
%>
<%
}
%>
思考?
如果现在一个公司有3000000个雇员呢?那么以上的程序如果运行的话,会如何呢?
发现如果全部列出来之后,页面的列表太长了,而且查找起来也不方便,所以一般的站点会选择部分的进行显示,例如:
• 第1页显示1~10条
• 第2页显示11~20条
3.2、分页的实现
分页的实现分为两种:
• 假分页:是将全部的数据取出,之后在页面中通过程序的算法实现分页的控制。本身不需要任何的数据库的单独支持,就是编写标准的SQL语句。假分页程序适合于程序的移植。
• 真分页:从数据库中取出指定范围的数据,进行显示。需要每个数据库都提供支持,而且各个数据库对于这方面的支持还不一样。移植性较差。
3.3、假分页
3.3.1、第一种实现
实现部分读取
实现的原理在于只显示需要的数据,而不需要的数据全部取消掉。
list_02.jsp:
<%@ page contentType="text/html;charset=GBK"%>
<%@ page import="java.sql.*"%>
<%--
查询出EMP表中的全部数据,使用假分页
--%>
<%!
public static final String DBDRIVER = "oracle.jdbc.driver.OracleDriver" ;
public static final String DBURL = "jdbc:oracle:thin:@localhost:1521:MLDN" ;
public static final String DBUSER = "scott" ;
public static final String DBPASS = "tiger" ;
%>
<%
Connection conn = null ;
PreparedStatement pstmt = null ;
ResultSet rs = null ;
%>
<%!
// 当前所在的页数
int currentPage = 2 ;
// 每页显示的记录数
int lineSize = 3 ;
%>
<%
try{
%>
<%
Class.forName(DBDRIVER) ;
conn = DriverManager.getConnection(DBURL,DBUSER,DBPASS) ;
String sql = "SELECT empno,ename,job,sal,comm,hiredate FROM emp" ;
pstmt = conn.prepareStatement(sql) ;
rs = pstmt.executeQuery() ;
// 之前应该先把不需要的数据空出去
for(int i=0;i<(currentPage-1)*lineSize;i++){
rs.next() ;
}
%>
<center>
<table border="1" width="80%">
<tr>
<td>雇员编号</td>
<td>雇员姓名</td>
<td>雇员工作</td>
<td>雇员工资</td>
<td>雇员佣金</td>
<td>雇佣日期</td>
</tr>
<%
for(int i=0;i<lineSize;i++){
if(rs.next()){
int empno = rs.getInt(1) ;
String ename = rs.getString(2) ;
String job = rs.getString(3) ;
float sal = rs.getFloat(4) ;
float comm = rs.getFloat(5) ;
java.util.Date date = rs.getDate(6) ;
%>
<tr>
<td><%=empno%></td>
<td><%=ename%></td>
<td><%=job%></td>
<td><%=sal%></td>
<td><%=comm%></td>
<td><%=date%></td>
</tr>
<%
}
}
%>
</table>
</center>
<%
}catch(Exception e){
// 向tomcat中进行打印
System.out.println(e) ;
}finally{
%>
<%
rs.close() ;
pstmt.close() ;
conn.close() ;
%>
<%
}
%>
3.3.2、进一步修改
上面虽然已经成功的进行了分页的处理,但是其本身存在了一个问题,每次都要求用户自己手工去修改currentPage,所以,此时想种方式,让currentPage的值变活,由外部决定传入的内容是什么。
list_03.jsp:
<%@ page contentType="text/html;charset=GBK"%>
<%@ page import="java.sql.*"%>
<%--
查询出EMP表中的全部数据,使用假分页
--%>
<%!
public static final String DBDRIVER = "oracle.jdbc.driver.OracleDriver" ;
public static final String DBURL = "jdbc:oracle:thin:@localhost:1521:MLDN" ;
public static final String DBUSER = "scott" ;
public static final String DBPASS = "tiger" ;
%>
<%
Connection conn = null ;
PreparedStatement pstmt = null ;
ResultSet rs = null ;
%>
<%!
// 当前所在的页数
int currentPage = 1 ;
// 每页显示的记录数
int lineSize = 3 ;
%>
<%
try{
currentPage = Integer.parseInt(request.getParameter("cp")) ;
}catch(Exception e){}
%>
<%
try{
%>
<%
Class.forName(DBDRIVER) ;
conn = DriverManager.getConnection(DBURL,DBUSER,DBPASS) ;
String sql = "SELECT empno,ename,job,sal,comm,hiredate FROM emp" ;
pstmt = conn.prepareStatement(sql) ;
rs = pstmt.executeQuery() ;
// 之前应该先把不需要的数据空出去
for(int i=0;i<(currentPage-1)*lineSize;i++){
rs.next() ;
}
%>
<center>
<table border="1" width="80%">
<tr>
<td>雇员编号</td>
<td>雇员姓名</td>
<td>雇员工作</td>
<td>雇员工资</td>
<td>雇员佣金</td>
<td>雇佣日期</td>
</tr>
<%
for(int i=0;i<lineSize;i++){
if(rs.next()){
int empno = rs.getInt(1) ;
String ename = rs.getString(2) ;
String job = rs.getString(3) ;
float sal = rs.getFloat(4) ;
float comm = rs.getFloat(5) ;
java.util.Date date = rs.getDate(6) ;
%>
<tr>
<td><%=empno%></td>
<td><%=ename%></td>
<td><%=job%></td>
<td><%=sal%></td>
<td><%=comm%></td>
<td><%=date%></td>
</tr>
<%
}
}
%>
</table>
</center>
<%
}catch(Exception e){
// 向tomcat中进行打印
System.out.println(e) ;
}finally{
%>
<%
rs.close() ;
pstmt.close() ;
conn.close() ;
%>
<%
}
%>
以上的所有代码都是用户通过地址完成的,list_03.jsp?cp=3,但是实际情况下用户是不可能自己去输入这些内容的,所以一般在各个站点上都会看见以下的内容:
首页 上一页 下一页 尾7页
3.3.3、加入控制端
<script language="javaScript">
function go(temp){
document.spform.cp.value = temp ;
// 表单提交
document.spform.submit() ;
}
</script>
<form action="<%=URL%>" method="post" name="spform">
<input type="button" value="首页" onClick="go(1)">
<input type="button" value="上一页" onClick="go(<%=currentPage-1%>)">
<input type="button" value="下一页" onClick="go(<%=currentPage+1%>)">
<input type="button" value="尾页">
<input type="hidden" name="cp" value="">
当前在<font color="red"><%=currentPage%></font>页
</form>
但是加上之后程序依然存在问题,如果现在已经在第一页了,则还可以继续向上
3.3.4、控制端改进
如果已经是在第一页了,则首页和上一页应该消失,不让继续使用。
在button按钮之后使用disabled进行按钮功能的取消。
<form action="<%=URL%>" method="post" name="spform">
<input type="button" value="首页" onClick="go(1)" <%=currentPage==1?"disabled":""%>>
<input type="button" value="上一页" onClick="go(<%=currentPage-1%>)" <%=currentPage==1?"disabled":""%>>
<input type="button" value="下一页" onClick="go(<%=currentPage+1%>)">
<input type="button" value="尾页">
<input type="hidden" name="cp" value="">
当前在<font color="red"><%=currentPage%></font>页
</form>
如何求出尾页呢?有多少条记录就可能有多少页。需要求出总页数。
list_05.jsp:
<%@ page contentType="text/html;charset=GBK"%>
<%@ page import="java.sql.*"%>
<%--
查询出EMP表中的全部数据,使用假分页
--%>
<%!
public static final String DBDRIVER = "oracle.jdbc.driver.OracleDriver" ;
public static final String DBURL = "jdbc:oracle:thin:@localhost:1521:MLDN" ;
public static final String DBUSER = "scott" ;
public static final String DBPASS = "tiger" ;
%>
<%!
public static final String URL = "list_05.jsp" ;
%>
<%
Connection conn = null ;
PreparedStatement pstmt = null ;
ResultSet rs = null ;
%>
<%!
// 当前所在的页数
int currentPage = 1 ;
// 每页显示的记录数
int lineSize = 3 ;
// 总记录数
int allRecorders = 0 ;
// 总页数
int allPages = 0 ;
%>
<center>
<%
try{
%>
<%
Class.forName(DBDRIVER) ;
conn = DriverManager.getConnection(DBURL,DBUSER,DBPASS) ;
String sql = "SELECT COUNT(empno) FROM emp" ;
pstmt = conn.prepareStatement(sql) ;
rs = pstmt.executeQuery() ;
if(rs.next()){
allRecorders = rs.getInt(1) ;
}
// 总页数应该是计算出来的
allPages = (allRecorders + lineSize -1) / lineSize ;
%>
<%
try{
currentPage = Integer.parseInt(request.getParameter("cp")) ;
}catch(Exception e){}
%>
<script language="javaScript">
function go(temp){
document.spform.cp.value = temp ;
// 表单提交
document.spform.submit() ;
}
</script>
<form action="<%=URL%>" method="post" name="spform">
<input type="button" value="首页" onClick="go(1)" <%=currentPage==1?"disabled":""%>>
<input type="button" value="上一页" onClick="go(<%=currentPage-1%>)" <%=currentPage==1?"disabled":""%>>
<input type="button" value="下一页" onClick="go(<%=currentPage+1%>)" <%=currentPage==allPages?"disabled":""%>>
<input type="button" value="尾页" onClick="go(<%=allPages%>)" <%=currentPage==allPages?"disabled":""%>>
<input type="hidden" name="cp" value="">
当前在<font color="red"><%=currentPage%></font>页
</form>
<%
sql = "SELECT empno,ename,job,sal,comm,hiredate FROM emp" ;
pstmt = conn.prepareStatement(sql) ;
rs = pstmt.executeQuery() ;
// 之前应该先把不需要的数据空出去
for(int i=0;i<(currentPage-1)*lineSize;i++){
rs.next() ;
}
%>
<table border="1" width="80%">
<tr>
<td>雇员编号</td>
<td>雇员姓名</td>
<td>雇员工作</td>
<td>雇员工资</td>
<td>雇员佣金</td>
<td>雇佣日期</td>
</tr>
<%
for(int i=0;i<lineSize;i++){
if(rs.next()){
int empno = rs.getInt(1) ;
String ename = rs.getString(2) ;
String job = rs.getString(3) ;
float sal = rs.getFloat(4) ;
float comm = rs.getFloat(5) ;
java.util.Date date = rs.getDate(6) ;
%>
<tr>
<td><%=empno%></td>
<td><%=ename%></td>
<td><%=job%></td>
<td><%=sal%></td>
<td><%=comm%></td>
<td><%=date%></td>
</tr>
<%
}
}
%>
</table>
</center>
<%
}catch(Exception e){
// 向tomcat中进行打印
System.out.println(e) ;
}finally{
%>
<%
rs.close() ;
pstmt.close() ;
conn.close() ;
%>
<%
}
%>
3.3.5、控制端进一步完善
如果现在需要定位到那个页面,则只能一步一步的进行下页下一页的选择,最好可以提供一个下拉列表,通过此列表显示出全部的页数,让用户自己选择。
list_06.jsp:
<%@ page contentType="text/html;charset=GBK"%>
<%@ page import="java.sql.*"%>
<%--
查询出EMP表中的全部数据,使用假分页
--%>
<%!
public static final String DBDRIVER = "oracle.jdbc.driver.OracleDriver" ;
public static final String DBURL = "jdbc:oracle:thin:@localhost:1521:MLDN" ;
public static final String DBUSER = "scott" ;
public static final String DBPASS = "tiger" ;
%>
<%!
public static final String URL = "list_06.jsp" ;
%>
<%
Connection conn = null ;
PreparedStatement pstmt = null ;
ResultSet rs = null ;
%>
<%!
// 当前所在的页数
int currentPage = 1 ;
// 每页显示的记录数
int lineSize = 3 ;
// 总记录数
int allRecorders = 0 ;
// 总页数
int allPages = 0 ;
%>
<center>
<%
try{
%>
<%
Class.forName(DBDRIVER) ;
conn = DriverManager.getConnection(DBURL,DBUSER,DBPASS) ;
String sql = "SELECT COUNT(empno) FROM emp" ;
pstmt = conn.prepareStatement(sql) ;
rs = pstmt.executeQuery() ;
if(rs.next()){
allRecorders = rs.getInt(1) ;
}
// 总页数应该是计算出来的
allPages = (allRecorders + lineSize -1) / lineSize ;
%>
<%
try{
currentPage = Integer.parseInt(request.getParameter("cp")) ;
}catch(Exception e){}
%>
<script language="javaScript">
function go(temp){
document.spform.cp.value = temp ;
// 表单提交
document.spform.submit() ;
}
function goSel(){
go(document.spform.selcp.value) ;
}
</script>
<form action="<%=URL%>" method="post" name="spform">
<input type="button" value="首页" onClick="go(1)" <%=currentPage==1?"disabled":""%>>
<input type="button" value="上一页" onClick="go(<%=currentPage-1%>)" <%=currentPage==1?"disabled":""%>>
<input type="button" value="下一页" onClick="go(<%=currentPage+1%>)" <%=currentPage==allPages?"disabled":""%>>
<input type="button" value="尾页" onClick="go(<%=allPages%>)" <%=currentPage==allPages?"disabled":""%>>
跳到第
<SELECT name="selcp" onChange="goSel()">
<%
for(int x=1;x<=allPages;x++){
%>
<OPTION VALUE="<%=x%>" <%=currentPage==x?"SELECTED":""%>><%=x%></OPTION>
<%
}
%>
</SELECT>
页
<input type="hidden" name="cp" value="">
</form>
<%
sql = "SELECT empno,ename,job,sal,comm,hiredate FROM emp" ;
pstmt = conn.prepareStatement(sql) ;
rs = pstmt.executeQuery() ;
// 之前应该先把不需要的数据空出去
for(int i=0;i<(currentPage-1)*lineSize;i++){
rs.next() ;
}
%>
<table border="1" width="80%">
<tr>
<td>雇员编号</td>
<td>雇员姓名</td>
<td>雇员工作</td>
<td>雇员工资</td>
<td>雇员佣金</td>
<td>雇佣日期</td>
</tr>
<%
for(int i=0;i<lineSize;i++){
if(rs.next()){
int empno = rs.getInt(1) ;
String ename = rs.getString(2) ;
String job = rs.getString(3) ;
float sal = rs.getFloat(4) ;
float comm = rs.getFloat(5) ;
java.util.Date date = rs.getDate(6) ;
%>
<tr>
<td><%=empno%></td>
<td><%=ename%></td>
<td><%=job%></td>
<td><%=sal%></td>
<td><%=comm%></td>
<td><%=date%></td>
</tr>
<%
}
}
%>
</table>
</center>
<%
}catch(Exception e){
// 向tomcat中进行打印
System.out.println(e) ;
}finally{
%>
<%
rs.close() ;
pstmt.close() ;
conn.close() ;
%>
<%
}
%>
3.3.6、控制端进一步完善 —— 改变显示的记录数
修改lineSize变量。
list_07.jsp:
<%@ page contentType="text/html;charset=GBK"%>
<%@ page import="java.sql.*"%>
<%--
查询出EMP表中的全部数据,使用假分页
--%>
<%!
public static final String DBDRIVER = "oracle.jdbc.driver.OracleDriver" ;
public static final String DBURL = "jdbc:oracle:thin:@localhost:1521:MLDN" ;
public static final String DBUSER = "scott" ;
public static final String DBPASS = "tiger" ;
%>
<%!
public static final String URL = "list_07.jsp" ;
%>
<%
Connection conn = null ;
PreparedStatement pstmt = null ;
ResultSet rs = null ;
%>
<%
// 当前所在的页数
int currentPage = 1 ;
// 每页显示的记录数
int lineSize = 3 ;
// 总记录数
int allRecorders = 0 ;
// 总页数
int allPages = 0 ;
// 定义一个页数的选择范围
int pageScope[] = {3,5,10,15,20,25,30,50,100} ;
%>
<center>
<%
try{
%>
<%
Class.forName(DBDRIVER) ;
conn = DriverManager.getConnection(DBURL,DBUSER,DBPASS) ;
String sql = "SELECT COUNT(empno) FROM emp" ;
pstmt = conn.prepareStatement(sql) ;
rs = pstmt.executeQuery() ;
if(rs.next()){
allRecorders = rs.getInt(1) ;
}
%>
<%
try{
currentPage = Integer.parseInt(request.getParameter("cp")) ;
}catch(Exception e){}
try{
lineSize = Integer.parseInt(request.getParameter("ls")) ;
}catch(Exception e){}
// 总页数应该是计算出来的
allPages = (allRecorders + lineSize -1) / lineSize ;
%>
<script language="javaScript">
function go(temp){
document.spform.cp.value = temp ;
document.spform.ls.value = document.spform.sells.value ;
// 表单提交
document.spform.submit() ;
}
function goSel(){
document.spform.ls.value = document.spform.sells.value ;
go(document.spform.selcp.value) ;
}
function goSel2(){
document.spform.ls.value = document.spform.sells.value ;
go(1) ;
}
</script>
<form action="<%=URL%>" method="post" name="spform">
<input type="button" value="首页" onClick="go(1)" <%=currentPage==1?"disabled":""%>>
<input type="button" value="上一页" onClick="go(<%=currentPage-1%>)" <%=currentPage==1?"disabled":""%>>
<input type="button" value="下一页" onClick="go(<%=currentPage+1%>)" <%=currentPage==allPages?"disabled":""%>>
<input type="button" value="尾页" onClick="go(<%=allPages%>)" <%=currentPage==allPages?"disabled":""%>>
跳到第
<SELECT name="selcp" onChange="goSel()">
<%
for(int x=1;x<=allPages;x++){
%>
<OPTION VALUE="<%=x%>" <%=currentPage==x?"SELECTED":""%>><%=x%></OPTION>
<%
}
%>
</SELECT>
页
每页显示
<SELECT name="sells" onChange="goSel2()">
<%
for(int x=0;x<pageScope.length;x++){
%>
<OPTION VALUE="<%=pageScope[x]%>" <%=lineSize==pageScope[x]?"SELECTED":""%>><%=pageScope[x]%></OPTION>
<%
}
%>
</SELECT>
条记录
<input type="hidden" name="cp" value="">
<input type="hidden" name="ls" value="">
</form>
<%
sql = "SELECT empno,ename,job,sal,comm,hiredate FROM emp" ;
pstmt = conn.prepareStatement(sql) ;
rs = pstmt.executeQuery() ;
// 之前应该先把不需要的数据空出去
for(int i=0;i<(currentPage-1)*lineSize;i++){
rs.next() ;
}
%>
<table border="1" width="80%">
<tr>
<td>雇员编号</td>
<td>雇员姓名</td>
<td>雇员工作</td>
<td>雇员工资</td>
<td>雇员佣金</td>
<td>雇佣日期</td>
</tr>
<%
for(int i=0;i<lineSize;i++){
if(rs.next()){
int empno = rs.getInt(1) ;
String ename = rs.getString(2) ;
String job = rs.getString(3) ;
float sal = rs.getFloat(4) ;
float comm = rs.getFloat(5) ;
java.util.Date date = rs.getDate(6) ;
%>
<tr>
<td><%=empno%></td>
<td><%=ename%></td>
<td><%=job%></td>
<td><%=sal%></td>
<td><%=comm%></td>
<td><%=date%></td>
</tr>
<%
}
}
%>
</table>
</center>
<%
}catch(Exception e){
// 向tomcat中进行打印
System.out.println(e) ;
}finally{
%>
<%
rs.close() ;
pstmt.close() ;
conn.close() ;
%>
<%
}
%>





