分页技术:
如果数据有1000条,分页进行显示,每页显示10条,共100页;
分页的好处在于: 利于页面布局,且显示的效率高!
分页关键点:
1. 分页SQL语句;
2. 后台处理逻辑的实现: dao/service/servlet/JSP
分页技术实现的原理:
为了实现数据共享,我们使用PageBean来对分页相关的信息进行封装。
其中,PageBean中封装的内容主要有:
【 当前页,每页显示的行数,总记录数,总页数,查询到的该页数据(用List进行封装)】。
这样,在JSP层,从前台向后台请求的数据:当前页码;
在Servlet层获取请求参数,创建PageBean对象,封装当前页码到PageBean对象中;创建Service实例对象并调用其分页查询的方法:getAll(PageBean bean),将PageBean的引用作为参数传递给Service层。
在Service层,创建Dao实例,并调用其分页方法getAll(PageBean bean),同样将PageBean作为参数传递给Dao层
在Dao层,这里主要有两个重要的方法,第一是获取总记录数getTotalCount(),第二是获取当前分页对应的数据信息getAll(PageBean)
实现步骤:
0. 环境准备
a) 引入jar文件及引入配置文件
i. 数据库驱动包
ii. C3P0连接池: jar文件 及 配置文件
iii. DbUtis组件: 使用DbUtils组件,可以将连接管理交给DataSource来管理,就可以省略获取连接的过程
b) 公用类的设计: JdbcUtils.java
package cn.itcast.utils;
import javax.sql.DataSource;
import org.apache.commons.dbutils.QueryRunner;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/**
* 工具类
* 1. 初始化C3P0连接池
* 2. 创建DbUtils核心工具类对象
*
*/
public class JdbcUtils {
/**
* 1. 初始化C3P0连接池
*/
private static DataSource dataSource;
static {
dataSource = new ComboPooledDataSource();
}
/**
* 2. 创建DbUtils核心工具类对象
*/
public static QueryRunner getQueryRuner(){
// 创建QueryRunner对象,传入连接池对象
// 在创建QueryRunner对象的时候,如果传入了数据源对象;
// 那么在使用QueryRunner对象方法的时候,就不需要传入连接对象;
// 会自动从数据源中获取连接(不用关闭连接)
return new QueryRunner(dataSource);
}
}
1. 先设计:PageBean.java
PageBean用来保存分页调用过程中必要的参数:
private int currentPage = 1; // 当前页, 默认显示第一页
private int lineCountPerPage = 4; // 每页显示的行数(查询返回的行数), 默认每页显示4行
private int totalCount; // 总记录数
private int totalPage; // 总页数 = 总记录数 / 每页显示的行数 (+ 1)
private List<T> pageData; // 分页查询到的数据
getters & setters
2. Dao接口设计/实现: 2个方法
2.1 统计总记录数
public int getTotalCount()
2.2 dao层中分页查询的逻辑
public void getAll(PageBean<Employee> pb);
a. 获取记录总数
b. 计算当前页的起始行、返回的行数
SELECT * FROM employee LIMIT 0,4 --查询第一页
SELECT * FROM employee LIMIT 4,4 --第二页
SELECT * FROM employee LIMIT 8,4 --第三页
SELECT * FROM employee LIMIT 12,4 --第四页
从以上的查询规律中我们可以总结出起始页的计算方式:
(当前页-1)* 每页显示行数
int currentPage = pb.getCurrentPage(); //首次访问,默认当前页是0,其他情况根据参数传递
int index = (currentPage - 1) * pb.getLineCountPerPage(); // 计算查询的起始行
int count = pb.getLineCountPerPage(); //获取返回行数
c. 分页差询sql执行
String sql = "select * from employee limit ?,?";
QueryRunner qr = JdbcUtils.getQueryRuner();
List<Employee> pageData = qr.query(sql, new BeanListHandler<Employee>(Employee.class), index,count);
pb.setPageData(pageData); //到这里,数据已经通过PageBean的引用设置进去了,在servlet端只需取出来就行
bug: 当前jsp页面是首页,再点击上一页 报错,
当前页面是末页,再点击下一页时显示不对!
解决:在步骤a、b之间增加判断:
- 如果请求的当前页 <= 0 ,将当前页设置为1,即查询首页
- 如果当前页 > 最大页数 , 将当前页设置为最大页数
3. Service/Servlet
service中只是创建并调用Dao,没有复杂逻辑
我们看看Servlet中的代码:
String uri = "" ;
try {
//1. 从参数中获取“当前页”参数
String currentPage = (String)request.getParameter("currentPage");
//判断: 第一次访问时,参数是null,应默认给其赋值为“1”
if(currentPage ==null || "".equals(currentPage.trim())){
currentPage = "1";
}
//格式转换
int currentPageNum = Integer.parseInt(currentPage);
//2. 创建PageBean对象,设置当前页的参数进去
PageBean<Employee> pageBean = new PageBean<Employee>();
pageBean.setCurrentPage(currentPageNum);
//3. 调用Service
service.getAll(pageBean); //通过底层方法进行数据填充
//4. 保存pageBean 对象,到request域中
request.setAttribute("pageBean", pageBean);
//5. 跳转
uri = "/WEB-INF/list.jsp";
} catch (Exception e) {
// 如果出错,则跳转到错误页面,进行友好提示
uri = "/error/error.jsp";
}
request.getRequestDispatcher(uri).forward(request, response);
4. JSP页面的处理逻辑
<table border="1" width="80%" align="center" cellpadding="5" cellspacing="0">
<tr>
<td>序号</td>
<td>员工编号</td>
<td>员工姓名</td>
</tr>
<c:choose>
<c:when test="${not empty requestScope.pageBean.pageData}">
<c:forEach var="emp" items="${requestScope.pageBean.pageData }" varStatus="vs">
<tr>
<td>${vs.count }</td>
<td>${emp.empId }</td>
<td>${emp.empName }</td>
</tr>
</c:forEach>
</c:when>
<c:otherwise>
<tr>
<td colspan="3">对不起,没有你要找的数据</td>
</tr>
</c:otherwise>
</c:choose>
<tr>
<td colspan="3" align="center">
当前${requestScope.pageBean.currentPage }/${requestScope.pageBean.totalPage }页
<a href="${pageContext.request.contextPath }/IndexServlet?currentPage=1">首页</a>
<a href="${pageContext.request.contextPath }/IndexServlet?currentPage=${requestScope.pageBean.currentPage-1}">上一页 </a>
<a href="${pageContext.request.contextPath }/IndexServlet?currentPage=${requestScope.pageBean.currentPage+1}">下一页 </a>
<a href="${pageContext.request.contextPath }/IndexServlet?currentPage=${requestScope.pageBean.totalPage}">末页</a>
</td>
</tr>
</table>