Java实现后端分页
分页操作在开发中可以说是最基本的操作,特别是在做各种后台管理系统的时候,不可能一次性查询一千条、一万条数据。
这时候就需要进行分页操作。那么在Java后端当中是如何实现分页的呢?下面就来聊一聊Java后端分页。
Java分页原理
首先说说分页的原理。有几个名词需要解释一下,数据总数,每页显示的记录数,当前页,总页数。
.1.假设某张表中总条数: total
.2.每页显示记录数:pageSize
.3.当前页:pageNum
.4.总页数:pages
第一步:页面当中需要传入两个数据,每页显示的记录数和当前页;
第二步:查询某张表的总数赋值给total;
第三步:计算总页数 总页数 = Math.ceil(总条数 * 1.0 / 每页显示记录数);
第四步:封装结果返回数据。
说明:总条数 * 1.0表示把一个整数转换为double类型的数据进行计算,否则两个整数相除,计算结果就是一个整数会舍弃掉小数部分。
Math.ceil()表示向上取整。举例每页显示6条数据,如果总共有8条数据,应该显示为2页,而不是1页。
示例一:如果每页显示5条,总数据分别为15,16,19该显示为多少条数据。
Math.ceil(15 * 0.1 / 5) 为3,Math.ceil(16 * 0.1 / 5) 为4,Math.ceil(19 * 0.1 / 5) 为4。符合要求,重点需要理解当最后一页的数据不满一页时,也需要单独显示为一页。
Mysql分页原理
Mysql中分页需要使用一个关键字limit,语法如下
Select * from 表 limit offset,size;
后面跟一个参数或者是两个参数。只跟一个参数表示从第一条记录开始,取size条记录。
如果跟两个参数,第一个参数offset表示偏移量,第二个参数size表示获取的记录数。
下面来做一个简单的测试,建表语句如下,
DROP TABLE IF EXISTS page_test;
CREATE TABLE `page_test` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(16) DEFAULT NULL COMMENT '名称',
`age` int(11) DEFAULT '0' COMMENT '年龄',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='分页测试表';
测试数据如下,
INSERT INTO `manage`.`page_test` (`id`, `name`, `age`) VALUES ('1', '测试名称1', '1');
INSERT INTO `manage`.`page_test` (`id`, `name`, `age`) VALUES ('2', '测试名称2', '2');
INSERT INTO `manage`.`page_test` (`id`, `name`, `age`) VALUES ('3', '测试名称3', '3');
INSERT INTO `manage`.`page_test` (`id`, `name`, `age`) VALUES ('4', '测试名称4', '4');
INSERT INTO `manage`.`page_test` (`id`, `name`, `age`) VALUES ('5', '测试名称5', '5');
INSERT INTO `manage`.`page_test` (`id`, `name`, `age`) VALUES ('6', '测试名称6', '6');
INSERT INTO `manage`.`page_test` (`id`, `name`, `age`) VALUES ('7', '测试名称7', '7');
INSERT INTO `manage`.`page_test` (`id`, `name`, `age`) VALUES ('8', '测试名称8', '8');
INSERT INTO `manage`.`page_test` (`id`, `name`, `age`) VALUES ('9', '测试名称9', '9');
INSERT INTO `manage`.`page_test` (`id`, `name`, `age`) VALUES ('10', '测试名称10', '10');
下面进行查询测试:
SELECT * FROM page_test order by id asc limit 0,3;
SELECT * FROM page_test order by id asc limit 3;
上面两个查询语句结果一致。
SELECT * FROM page_test order by id asc limit 1, 3;
SELECT * FROM page_test order by id asc limit 3,3;
SELECT * FROM page_test order by id asc limit 6,3;
从查询的结果中可以看出,如果每页显示3条数据,limit 0,3表示查询第一页;limit 3,3表示查询第二页;limit 6, 3表示查询第3页。
因此可以推导出一个公式:查询起始位置 = (当前页 - 1) * 每页显示记录数。然后每次分页查询时,动态传入limit后面的两个参数即可。
Java代码实现示例
@Getter
@Setter
@NoArgsConstructor
public class PageReSult<T> {
// 数据总数
private Integer total;
// 当前页码
private Integer pageNum;
// 每页显示记录数
private Integer pageSize;
// 总页数
private Integer pages;
// 列表数据
private List<T> data;
}
说明: Set/get/构造函数使用的是Lombok实现。
分页思路如下:
.a.获取页面中传递的参数;
.b.查询总条数;
.c.计算mysql中的起始查询位置,查询当前页的数据;
.d.获取当前页的数据;
.e.封装查询结果;
.f.返回数据;
具体示例代码如下
@WebServlet("/pageTest")
public class PageTestApi extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取分页参数
String pageNumStr = req.getParameter("pageNum");
String pageSizeStr = req.getParameter("pageSize");
// 将分页参数转换为整数
Integer pageNum = Integer.parseInt(pageNumStr);
Integer pageSize = Integer.parseInt(pageSizeStr);
System.out.println("pageNum--->" + pageNum + ";pageSize=" + pageSize);
// 查询总条数
String countSql = " SELECT count(*) total FROM page_test ";
PreparedStatement stmt = null;
Integer total = 0;
PageReSult pageReSult = new PageReSult();
// 使用工具类获取数据库连接
try (Connection conn = JDBCUtils.getConnection();){
// 获取数据库操作对象 prepareStatement 可以预编译sql防止sql注入
stmt = conn.prepareStatement(countSql);
// 执行查询
ResultSet rs = stmt.executeQuery();
// 获取查询结果
if(rs.next()){
total = rs.getInt("total");
}
System.out.println("total--->" + total);
// 计算 mysql 中 limit 查询的起始位置
int start = (pageNum - 1) * pageSize;
// 查询分页数据,最好按照某个字段进行排序,否则查询结果可能会不准确
String selectSql = " SELECT * FROM page_test order by id asc limit ?,?";
stmt = conn.prepareStatement(selectSql);
stmt.setObject(1, start);
stmt.setObject(2, pageSize);
rs = stmt.executeQuery();
List<EntityTest> data = new ArrayList<>();
// 获取查询结果集
while (rs.next()){
EntityTest entityTest = new EntityTest();
entityTest.setId(rs.getLong("id"));
entityTest.setName(rs.getString("name"));
entityTest.setAge(rs.getInt("age"));
data.add(entityTest);
}
// 计算总页数
Integer pages = (int)Math.ceil(total * 1.0 / pageSize);
// 封装查询结果
pageReSult.setTotal(total);
pageReSult.setPages(pages);
pageReSult.setPageNum(pageNum);
pageReSult.setData(data);
pageReSult.setPageNum(pageNum);
} catch (SQLException e) {
throw new RuntimeException("分页查询错误!");
}
// 使用工具类返回查询结果
CommonResult.success(resp, pageReSult);
}
}
每页查询3条数据,测试结果如下:
第一页数据,重点看id为1,2,3.
第二页数据,id为4,5,6
如果每页查询5条数据,查询第二页结果也正确。到此Java后端分页查询功能全部实现。有其他建议的小伙伴,欢迎留言讨论。