分页技术总结
- 定义一个包装类,将分页所有需要的信息都封装到这个对象中,从后台通过域传给前台使用,也传给dao层查询数据使用
- 过程: 1, 前台到后台
- 前台传给后台的参数,主要是当前页码,当用户通过点击具体页面,或者前一页,后一页码,超链接中通过el表达式带有参数传给后台,后台进行查询,再返回相应的结果.这里要注意,在用户第一次访问这个页面时,默认显示第一页,所以后台首先做一个判断,当前台没有参数传来时(参数为null),即默认赋值为1的操作.
import java.util.List;
public class Page<T> {
//设置每页的显示条数,一般是固定的
private int page_size;
//设置总页数,通过总行数,每页显示条数,计算而得
private int pages;
//设置总行数,数据库查询记录数
private int rows;
//设置起始行号
private int startRow;
//设置当前页码
private int currentPage;
//设置页码,用来前台页面需要显示多少页码使用
private int[] nums;
//保存查询结果的属性
private List<T> list;
public int getPage_size() {
return page_size;
}
public void setPage_size(int page_size) {
this.page_size = page_size;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
public int getRows() {
return rows;
}
public void setRows(int rows) {
this.rows = rows;
}
public int getStartRow() {
return startRow;
}
public void setStartRow(int startRow) {
this.startRow = startRow;
}
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int[] getNums() {
return nums;
}
public void setNums(int[] nums) {
this.nums = nums;
}
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
}
业务层–service处理
service层通过调用dao层获取需要的数据, 然后进行对对象的封装操作,进行相应的逻辑处理
public Page findDepartmentsByCurrentPage(int currentPage) throws Exception {
//这里以每页显示4个为例
int page_size = 4;
//调用dao层方法, 获取一共有多少行数据
int rows = departmentsDao.getRows();
if(rows != 0){
//计算总共有多少页数,如果总行数除以每页要显示的个数,是一个整数,则巧好是整数页,
//如果有余数,则结果还得加1,最后一页的数据显示不够4个而已
/*
如 rows page_size pages
9 4 2+1=3
8 4 2
*/
int pages = rows % page_size == 0 ? rows / page_size : rows / page_size + 1;
//这里就是判断,防止前台页面已经在第一页,或者最后一页时,还向前或者往后,当然前台也会做一个判断处理
if(currentPage < 1){
currentPage = 1;
}
if(currentPage > pages){
currentPage = pages;
}
//数据库查询 select * from deptments limit 起始位置(从0开始), 长度
/* 页码 起始位置 长度
1 0 4
2 4 4
3 8 4
规律:
... (当前页码-1)*每页显示个数 4
*/
int startRow = (currentPage - 1) * page_size;
//创建page对象,进行对数据的封装,用来传值,java中常用方式,用对象来封装多个值,当有多个不同类的值混合时.
//定义一个包装类,将多个类在封装到这个包装类中,该包装类中也可有集合,数组等属性
Page page = new Page();
page.setCurrentPage(currentPage);
page.setPage_size(page_size);
page.setPages(pages);
page.setRows(rows);
page.setStartRow(startRow);
/*
* 当前页为1 123
* 当前页为2 123
* 当前页为3 234
* 当前页为4 345
* 当前页为n n-1 n n+1
* 当前页为pages n-2 n-1 n
* */
//当数据过多时,要求导航页码条只显示部分页码,
//可封装一个数组到page对象中,这样可自定义显示多少个页码了
// 如: 首页 << 1, 2, 3 >> 末页 这样格式,自定义
int[] nums = new int[3];
if(currentPage == 1){
for(int i = 1;i <= 3;i++){
nums[i-1] = i;
}
}else if(currentPage == pages){
for(int i=1; i<=3; i++){
nums[i-1]=currentPage-3+i;
}
}else{
for(int i = 1;i <= 3;i++){
nums[i-1] = currentPage - 2 + i ;
}
}
page.setNums(nums);
//把对象传给dao层方法,dao中就可以用page中的数据进行数据库查询了
List<Departments>depts = departmentsDao.selectDepartmentsAll(page);
page.setList(depts);
return page;
}
return null;
}
dao层—持久层(直接与数据库交互的)
//该方法查询有多少条数据,用来后面结合每页显示个数,计算多少页
public int getRows() throws Exception {
//采用的C3p0连接池 和DBUtils工具类
Connection conn = C3P0Utils.getConnection();
QueryRunner run = new QueryRunner();
int rows = 0;
try {
String sql = "select count(*) cou from departments";
Long cou = (Long) run.query(conn, sql, new ScalarHandler());
rows= cou.intValue();
} catch (Exception e) {
e.printStackTrace();
throw new Exception();
} finally{
C3P0Utils.close(conn, null, null);
}
return rows;
}
//传入的是page对象,里面封装了起始位置,以及每页显示个数
public List<Departments> selectDepartmentsAll(Page page) throws Exception {
Connection conn = C3P0Utils.getConnection();
QueryRunner run = new QueryRunner();
List<Departments>depts = null;
try {
//第一个问号,传入起始位置,第二个为每页个数
String sql = "select * from departments limit ?,?";
depts = run.query(conn, sql, new BeanListHandler<>(Departments.class), page.getStartRow(),page.getPage_size());
} catch (Exception e) {
e.printStackTrace();
throw new Exception();
} finally{
C3P0Utils.close(conn, null, null);
}
return depts;
}
前端处理
这里套用了bootstrap前端框架的组件,看着很多,实则大部分都是直接套用,
核心是从域中获取后台传来的page对象,里面封装很多数据,通过el表达式获取出来即可
<!--分页部分 -->
<div class="row" align="center">
//这里首先做判断page对象不为空,el表达式里面可以做运算判断
<c:if test="${page.list!=null}">
<nav aria-label="Page navigation">//套用部分,不用理会,里面的样式修饰都是套用
<ul class="pagination">
//这个li标签是首页,注意将参数固定为1传递
<li>
<a href="${pageContext.request.contextPath}/listDepart?method=list¤tPage=1" aria-label="Previous">
<span aria-hidden="true">首页</span>
</a>
</li>
<!-- 如果当前页是第一页 -->,如果是,会引用样式disabled,则上一页的超链接会是禁用样式,注意要把href 设置为禁止跳转,javascript:void(0),让超链接失去跳转功能,若不设置,即使为空,也会跳转到空白页面的
<c:if test="${page.currentPage==1}">
<li class="disabled">
<a href="javascript:void(0)" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
</c:if>
<!-- 当前页不等于1情况 -->
<c:if test="${page.currentPage!=1}">
<li>
<a href="${pageContext.request.contextPath}/listDepart?method=list¤tPage=${page.currentPage-1}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
</c:if>
<!--从数组循环获取页码 -->
<c:forEach items="${page.nums}" var="num">
<c:if test="${page.currentPage==num}">
<li class="active"><a href="javascript:void(0);">${num}</a></li>
</c:if>
<c:if test="${page.currentPage!=num}">
<li><a href="${pageContext.request.contextPath}/listDepart?method=list¤tPage=${num}">${num}</a></li>
</c:if>
</c:forEach>
<!-- 下一页的超链接,这里没有判断当前页是否为最后页,是则要在鼠标放上面呈现禁用标志,和上一页一样-->
<li>
<a href="${pageContext.request.contextPath}/listDepart?method=list¤tPage=${page.currentPage+1}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
<!-- 末页直接获取page对象中页面总数的数值 -->
<li>
<a href="${pageContext.request.contextPath}/listDepart?method=list¤tPage=${page.pages}" aria-label="Next">
<span aria-hidden="true">末页</span>
</a>
</li>
</ul>
</nav>
</c:if>
</div>
学习总结,水平有限,如有错误,敬请指正,感激不尽!