分页工具类PaginationHelper的设计与实现

背景

在日常开发中,我们经常需要处理分页查询的场景。比如从数据库分页查询数据,或者调用第三方API进行分页查询。这些分页查询的逻辑往往比较类似:

  1. 设定页码(pageIndex)和每页大小(pageSize)
  2. 循环查询直到没有更多数据
  3. 处理每一页的数据

为了避免重复编写这些模板代码,我设计了一个通用的分页工具类PaginationHelper。

核心实现

PaginationHelper的核心是一个静态方法paginateAndProcess,它接收三个参数:

  1. fetchPageFunction: 分页查询函数,传入页码和每页大小,返回分页结果
  2. pageSize: 每页大小
  3. processDataFunction: 处理每页数据的函数

代码实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@Slf4j
public class PaginationHelper {
/**
* 通用分页遍历方法
*
* @param fetchPageFunction 分页查询函数,接收 pageIndex 和 pageSize,返回 PageResp<T>
* @param pageSize 每页大小
* @param processDataFunction 处理数据的函数,接收 List<T> 数据
* @param <T> 数据类型
*/
public static <T> void paginateAndProcess(
BiFunction<Integer, Integer, PageResp<T>> fetchPageFunction,
int pageSize,
Consumer<List<T>> processDataFunction
) {
int pageIndex = 1;
boolean hasMore = true;
int totalProcessed = 0;
while (hasMore) {
PageResp<T> pageResp = fetchPageFunction.apply(pageIndex, pageSize);
// 处理异常情况
if (pageResp == null) {
log.error("Failed to retrieve page {}, stopping pagination", pageIndex);
return;
}
List<T> dataList = pageResp.getDataList();
if (dataList == null || dataList.isEmpty()) {
log.info("Page {} data is empty, ending pagination", pageIndex);
hasMore = false;
break;
}
// 处理数据
processDataFunction.accept(dataList);
totalProcessed += dataList.size();
// 计算分页
long total = pageResp.getTotal();
long totalPages = (total + pageSize - 1) / pageSize;
if (pageIndex >= totalPages) {
hasMore = false;
} else {
pageIndex++;
}
}
log.info("Pagination completed. Total entries processed: {}", totalProcessed);
}
}
1
2
3
4
5
6
7
8
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageResp<T> implements Serializable {
public static final long serialVersionUID = 1L;
private List<T> dataList;
private Long total;
}

使用示例

以下是一个简单的使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 定义分页查询函数
BiFunction<Integer, Integer, PageResp<User>> fetchUsers = (pageIndex, pageSize) -> {
return userService.queryByPage(pageIndex, pageSize);
};

// 定义数据处理函数
Consumer<List<User>> processUsers = users -> {
users.forEach(user -> {
// 处理每个用户数据
System.out.println(user.getName());
});
};

// 使用PaginationHelper进行分页处理
PaginationHelper.paginateAndProcess(fetchUsers, 20, processUsers);

特点与优势

  1. 通用性强: 通过泛型和函数式接口,可以处理任何类型的分页数据

  2. 异常处理: 内置了基本的异常处理逻辑,避免因异常导致程序中断

  3. 日志完善: 记录了关键节点的日志,方便排查问题

  4. 使用简单: 只需要提供查询函数和处理函数即可使用

  5. 解耦合: 将分页逻辑与业务逻辑解耦,提高代码复用性

总结

PaginationHelper是一个简单但实用的分页工具类,它可以帮助我们:

  1. 减少重复代码
  2. 提高代码可读性
  3. 统一异常处理
  4. 方便日志记录

在需要分页查询的场景下,都可以考虑使用这个工具类来简化开发。