分页功能在网页中是非常常见的一个功能,其作用也就是将数据分割成多个页面来进行显示。
当我们不使用分页功能的时候,会面临许多的问题:
分页的实现分为真分页和假分页两种,也就是物理分页和逻辑分页。
1.真分页(物理分页):
SELECT * FROM xxx [WHERE...] LIMIT #{param1}, #{param2}
第一个参数是开始数据的索引位置
第二个参数是要查询多少条数据2.假分页(逻辑分页):
对于假分页的实现方式很简单,只需要准备一个集合保存从数据库中取出的所有数据,然后根据当前页面的码数,取出对应范围的数据显示就好了,我们这里基于物理分页来实现。
可以发现页面功能中需要用到的数据有两个是需要通过 SQL 语句查询得来的:一个是页面中显示的数据 List<Student> ,另一个是数据的总条数 totalCount,分别对应以下两条 SQL 语句:
SELECT * FROM student LIMIT #{param1}, #{param2}
SELECT COUNT(*) FROM student
通过计算得到的数据有:
用户传递的数据:
所有我们可以创建一个 Page 工具类备用:
public class Page {
int start; // 开始数据的索引
int count; // 每一页的数量
int total; // 总共的数据量
/**
* 提供一个构造方法
* @param start
* @param count
*/
public Page(int start, int count) {
super();
this.start = start;
this.count = count;
}
/**
* 判断是否有上一页
* @return
*/
public boolean isHasPreviouse(){
if(start==0)
return false;
return true;
}
/**
* 判断是否有下一页
* @return
*/
public boolean isHasNext(){
if(start==getLast())
return false;
return true;
}
/**
* 计算得到总页数
* @return
*/
public int getTotalPage(){
int totalPage;
// 假设总数是50,是能够被5整除的,那么就有10页
if (0 == total % count)
totalPage = total /count;
// 假设总数是51,不能够被5整除的,那么就有11页
else
totalPage = total / count + 1;
if(0==totalPage)
totalPage = 1;
return totalPage;
}
/**
* 计算得到尾页
* @return
*/
public int getLast(){
int last;
// 假设总数是50,是能够被5整除的,那么最后一页的开始就是45
if (0 == total % count)
last = total - count;
// 假设总数是51,不能够被5整除的,那么最后一页的开始就是50
else
last = total - total % count;
last = last<0?0:last;
return last;
}
/* getter and setter */
}
首先我们在前台需要完成我们分页条的设计,这里可以直接引入 Bootstrap 来完成:
上面是使用 Bootstrap 实现一个分页条的简单例子,如果不熟悉的童鞋可以去菜鸟教程中查看:点这里
为了便于理解,我们先来实现一个简单版本的分页条吧:
<li>
<a href="?page.start=0">
<span>«</span>
</a>
</li>
<li >
<a href="?page.start=${page.start-page.count}">
<span>‹</span>
</a>
</li>
<li >
<a href="?page.start=${page.start+page.count}">
<span>›</span>
</a>
</li>
<li >
<a href="?page.start=${page.last}">
<span>»</span>
</a>
</li>
<c:forEach begin="0" end="${page.totalPage-1}" varStatus="status">
<li>
<a href="?page.start=${status.index*page.count}" class="current">${status.count}</a>
</li>
</c:forEach>
<nav>
<ul class="pagination">
<li>
<a href="?page.start=0">
<span>«</span>
</a>
</li>
<li >
<a href="?page.start=${page.start-page.count}">
<span>‹</span>
</a>
</li>
<c:forEach begin="0" end="${page.totalPage-1}" varStatus="status">
<li>
<a href="?page.start=${status.index*page.count}" class="current">${status.count}</a>
</li>
</c:forEach>
<li >
<a href="?page.start=${page.start+page.count}">
<span>›</span>
</a>
</li>
<li >
<a href="?page.start=${page.last}">
<span>»</span>
</a>
</li>
</ul>
</nav>
1.写好头和尾
<nav class="pageDIV">
<ul class="pagination">
.....
</ul>
</nav>
2.写好«
‹
这两个功能按钮
使用 <c:if>
标签来增加边界判断,如果没有前面的页码了则设置为disable状态
<li <c:if test="${!page.hasPreviouse}">class="disabled"</c:if>>
<a href="?page.start=0">
<span>«</span>
</a>
</li>
<li <c:if test="${!page.hasPreviouse}">class="disabled"</c:if>>
<a href="?page.start=${page.start-page.count}">
<span>‹</span>
</a>
</li>
再通过 JavaScrip 代码来完成禁用功能:
<script>
$(function () {
$("ul.pagination li.disabled a").click(function () {
return false;
});
});
</script>
3.完成中间页码的编写
<c:forEach begin="0" end="${page.totalPage-1}" varStatus="status">
<c:if test="${status.count*page.count-page.start<=30 && status.count*page.count-page.start>=-10}">
<li <c:if test="${status.index*page.count==page.start}">class="disabled"</c:if>>
<a
href="?page.start=${status.index*page.count}"
<c:if test="${status.index*page.count==page.start}">class="current"</c:if>
>${status.count}</a>
</li>
</c:if>
</c:forEach>
从 0
循环到 page.totalPage - 1
,varStatus
相当于是循环变量
首页在项目中引入上面提到的 Page 工具类,然后我们在 DAO 类中使用 LIMIT 关键字来查询数据库中的信息:
public List<Student> list() {
return list(0, Short.MAX_VALUE);
}
public List<Student> list(int start, int count) {
List<Student> students = new ArrayList<>();
String sql = "SELECT * FROM student ORDER BY student_id desc limit ?,?";
try (Connection c = DBUtil.getConnection(); PreparedStatement ps = c.prepareStatement(sql)) {
ps.setInt(1, start);
ps.setInt(2, count);
// 获取结果集...
} catch (SQLException e) {
e.printStackTrace();
}
return students;
}
在 Servlet 中获取分页参数并使首页显示的 StudentList 用 page 的参数来获取:
// 获取分页参数
int start = 0;
int count = 10;
try {
start = Integer.parseInt(req.getParameter("page.start"));
count = Integer.parseInt(req.getParameter("page.count"));
} catch (Exception e) {
}
Page page = new Page(start, count);
List<Student> students = studentDAO.list(page.getStart(), page.getCount());
....
// 共享数据
req.setAttribute("page", page);
req.setAttribute("students", students);
以上即可完成分页功能,但这是基于 Servlet 的版本,在之前写过的项目(学生管理系统(简易版))中实际的使用了这种方法,感兴趣的可以去看一下。
在 SSM 项目中,我们可以使用 MyBatis 的一款分页插件: PageHelper 来帮助我们更加简单的完成分页的需求,官网在这里: PageHelper
在这里,我们演示一下如何使用上面的工具重构我们之前写过的 SSM 项目 —— 学生管理系统-SSM 版
PageHelper 需要依赖两个 jar 包,我们直接在 pom.xml 中增加两个 jar 包依赖:
<!-- pageHelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.2-beta</version>
</dependency>
<!--jsqlparser-->
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>1.0</version>
</dependency>
在 MyBatis 的 SessionFactory 配置中新增加一个属性名 plugins 的配置:
<!-- 配置SqlSessionFactory对象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
<!-- 扫描entity包 使用别名 -->
<property name="typeAliasesPackage" value="cn.wmyskxz.entity"/>
<!-- 扫描sql配置文件:mapper需要的xml文件 -->
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
<!-- 让MyBatis支持PageHelper插件 -->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<!--使用下面的方式配置参数,一行配置一个 -->
<value>
</value>
</property>
</bean>
</array>
</property>
</bean>
首先我们把 LIMIT 关键字从映射文件中干掉:
<!-- 查询从start位置开始的count条数据-->
<select id="list" resultMap="student">
SELECT * FROM student ORDER BY student_id desc
</select>
然后注释掉查询数据总条数的 SQL 语句:
<!--<!– 查询数据条目 –>-->
<!--<select id="getTotal" resultType="int">-->
<!--SELECT COUNT(*) FROM student-->
<!--</select>-->
在 Dao 类和 Service 类中修改相应的地方:
然后修改掉 StudentController 中的方法:
@RequestMapping("/listStudent")
public String listStudent(HttpServletRequest request, HttpServletResponse response) {
// 获取分页参数
int start = 0;
int count = 10;
try {
start = Integer.parseInt(request.getParameter("page.start"));
count = Integer.parseInt(request.getParameter("page.count"));
} catch (Exception e) {
}
Page page = new Page(start, count);
// 使用 PageHelper 来设置分页
PageHelper.offsetPage(page.getStart(),page.getCount());
List<Student> students = studentService.list();
// 使用 PageHelper 来获取总数
int total = (int) new PageInfo<>(students).getTotal();
page.setTotal(total);
request.setAttribute("students", students);
request.setAttribute("page", page);
return "listStudent";
}
重启服务器,能看到也能够正确的使用分页功能。
其实我自己对于这个工具比较无感..因为只是弱化了少一部分的功能,并没有我想象中的那样 “智能” ,也没有看到什么好的博文能够点通我的认知,希望了解的大大们能无私分享一下,谢谢!
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有