当数据有几万、几十万甚至上百万时,用户必须要拖动页面才能浏览更多的数据,很大程度的影响了用户体验。这时可以使用分页来显示数据,能够使数据更加清晰直观,且不受数量的限制。
分页的方式主要分为两种:
- 将查询结果以集合等形式保存在内存中,翻页时从中取出一页数据显示。该方法可能导致用户浏览到的是过期数据,且如果数据量非常大,查询一次数据就会耗费很长时间,存储的数据也会占用大量的内存开销。
- 每次翻页时只从数据库中检索出本页需要的数据。虽然每次翻页都需要查询数据库,但查询的记录数相对较少,总体开销不大,再配以连接池等技术进行优化,可以达到比较高的效率。
实现分页步骤
实现数据的分页显示,需要以下几个关键步骤:
1)确定每页显示的数据数量
确定每页显示的记录条数,即每次从数据库中需要查询出多少条记录用于页面显示。通常这个数量可以在开发时定义好,也可以由用户来选择。
2)计算显示的总页数
根据每页显示的记录条数计算总页数,即会产生多少页数据。显示的记录数量是已知的,而数据库中符合条件的记录总数是未知的,因此想要得到总页数,需要先得到符合条件的记录总数。
3)编写SQL语句
使用相应的 SQL 语句实现分页需求。例如,MySQL 中的 LIMIT 子句,SqlServer 中的 TOP、Oracle 中的 ROWNUM 等。
注意:本节使用的是 MySQL 数据库。不同的数据库厂商实现分页的 SQL 语句会存在差异,因此在实际应用中根据数据库的不同,需要修改相应的 SQL 语句。
示例
创建 websites 数据表,并插入数据。websites 数据表结构和数据参见 JSP 连接数据库
Website 类的代码如下:
实例
package com.runoops.entity;
public class Website {
private int id;
private String name;
private String url;
private int age;
private String country;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
基于方便代码管理的考虑,将有关分页的数据封装到一个 Page 类中,其中包括每页显示的数据数量、数据的总数量、显示的总页数、当前页码、每页显示的数据集合。Page 代码如下:
实例
package com.runoops.utils;
import java.util.List;
import com.runoops.entity.Website;
public class Page {
// 总页数
private int totalPageCount = 0;
// 页面大小,即每页显示记录数
private int pageSize = 3;
// 记录总数
private int totalCount;
// 当前页码
private int currPageNo = 1;
// 每页网站集合
private List<Website> websiteList;
public int getTotalPageCount() {
return totalPageCount;
}
public void setTotalPageCount(int totalPageCount) {
this.totalPageCount = totalPageCount;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
if (pageSize > 0)
this.pageSize = pageSize;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
System.out.println(totalCount);
if (totalCount > 0) {
this.totalCount = totalCount;
// 计算总页数
totalPageCount = this.totalCount % pageSize == 0 ? (this.totalCount / pageSize)
: (this.totalCount / pageSize + 1);
}
}
public int getCurrPageNo() {
if (currPageNo == 0)
return 0;
return currPageNo;
}
public void setCurrPageNo(int currPageNo) {
if (currPageNo > 0)
this.currPageNo = currPageNo;
}
public List<Website> getWebsiteList() {
return websiteList;
}
public void setWebsiteList(List<Website> websiteList) {
this.websiteList = websiteList;
}
}
在 setTotalCount() 方法中,根据记录总数和每页显示记录数计算出总页数,使用三元运算符?:
进行处理。如果记录总数能被每页显示记录数整除,则总页数为两者的商,如果不能被整除,则余出的记录数单独列为一页,总页数为两者的商再加 1。
WebsiteDao 代码如下:
package com.runoops.dao;
import java.util.List;
import com.runoops.entity.Website;
public interface WebsiteDao {
// 查询总条数
public int getTotcalCount();
//根据起始下标和每页显示数量查询数据
public List<Website> getPageWebsiteList(int pageNo, int pagesize);
}
WebsiteDaoImpl 代码如下:
实例
package com.runoops.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.runoops.entity.Website;
public class WebsiteDaoImpl implements WebsiteDao {
/**
* 连接数据库
*/
public static Connection getConnection() {
Connection con = null;
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/runoops?characterEncoding=utf-8&useSSL=false", "root", "123456");
} catch (Exception e) {
e.printStackTrace();
}
return con;
}
/**
* 查询总条数
*/
@Override
public int getTotcalCount() {
int count = 0;
try {
Connection con = getConnection();
String sql = "SELECT COUNT(id) FROM websites";
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
rs.next();
count = rs.getInt(1);
} catch (SQLException e) {
e.printStackTrace();
}
return count;
}
@Override
public List<Website> getPageWebsiteList(int pageNo, int pagesize) {
PreparedStatement ps;
ResultSet rs;
List<Website> list = new ArrayList<Website>();
try {
Connection con = getConnection();
String sql = "SELECT * FROM websites LIMIT " + (pageNo - 1) * pagesize + "," + pagesize;
ps = con.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()) {
Website website = new Website();
website.setId(rs.getInt(1));
website.setName(rs.getString(2));
website.setUrl(rs.getString(3));
website.setAge(rs.getInt(4));
website.setCountry(rs.getString(5));
list.add(website);
}
con.close();
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
}
website.jsp 页面代码如下:
实例
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page
import="java.util.*,com.runoops.dao.*,com.runoops.entity.*,com.runoops.utils.*"%>
<html>
<head>
<title>JSP 分页 - 自学教程(runoops.com)</title>
</head>
<body>
<%
WebsiteDao websiteDao = new WebsiteDaoImpl();
String pageNo = request.getParameter("page") != null ? request.getParameter("page") : "1";
int currPageNo = Integer.parseInt(pageNo);
Page p = new Page();
p.setCurrPageNo(currPageNo);
p.setPageSize(3);
p.setTotalCount(websiteDao.getTotcalCount());
List<Website> websiteList = websiteDao.getPageWebsiteList(p.getCurrPageNo(), p.getPageSize());
p.setWebsiteList(websiteList);
out.print("<h1>当前页面: " + currPageNo + "</h1>");
out.print("<table border='1' cellpadding='4' width='60%'>");
out.print("<tr><th>id</th><th>name</th><th>url</th><th>age</th><th>country</th></tr>");
for (Website e : websiteList) {
out.print("<tr><td>" + e.getId() + "</td><td>" + e.getName() + "</td><td>" + e.getUrl() + "</td><td>"
+ e.getAge() + "</td><td>" + e.getCountry() + "</td></tr>");
}
out.print("</table>");
for (int i = 1; i <= p.getTotalPageCount(); i++) {
%>
<a href="website.jsp?page=<%=i%>"><%=i%></a>
<%
}
%>
</body>
</html>
运行结果如下: