本文目录导读:

我来给你分享一个通用的Java分页模块设计方案,包含完整的代码实现:
通用分页请求对象
/**
* 通用分页请求参数
*/
public class PageRequest {
// 当前页码,从1开始
private Integer pageNum = 1;
// 每页显示条数
private Integer pageSize = 10;
// 排序字段
private String orderBy;
// 排序方式:asc/desc
private String orderType = "asc";
// 构造函数
public PageRequest() {}
public PageRequest(Integer pageNum, Integer pageSize) {
this.pageNum = pageNum;
this.pageSize = pageSize;
}
// 计算数据库偏移量
public Integer getOffset() {
return (pageNum - 1) * pageSize;
}
// getters and setters
public Integer getPageNum() {
return pageNum;
}
public void setPageNum(Integer pageNum) {
if (pageNum == null || pageNum < 1) {
this.pageNum = 1;
} else {
this.pageNum = pageNum;
}
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
if (pageSize == null || pageSize < 1) {
this.pageSize = 10;
} else {
this.pageSize = Math.min(pageSize, 100); // 限制最大100条
}
}
public String getOrderBy() {
return orderBy;
}
public void setOrderBy(String orderBy) {
this.orderBy = orderBy;
}
public String getOrderType() {
return orderType;
}
public void setOrderType(String orderType) {
if ("asc".equalsIgnoreCase(orderType) || "desc".equalsIgnoreCase(orderType)) {
this.orderType = orderType.toLowerCase();
}
}
}
通用分页响应对象
import java.util.Collections;
import java.util.List;
/**
* 通用分页响应结果
*/
public class PageResult<T> {
// 当前页码
private Integer pageNum;
// 每页条数
private Integer pageSize;
// 总条数
private Long total;
// 总页数
private Integer pages;
// 数据列表
private List<T> list;
// 是否有上一页
private Boolean hasPrevious;
// 是否有下一页
private Boolean hasNext;
public PageResult() {
this.list = Collections.emptyList();
}
/**
* 构建分页结果
*/
public static <T> PageResult<T> build(List<T> list, Long total, PageRequest pageRequest) {
PageResult<T> result = new PageResult<>();
result.setList(list == null ? Collections.emptyList() : list);
result.setTotal(total == null ? 0L : total);
result.setPageNum(pageRequest.getPageNum());
result.setPageSize(pageRequest.getPageSize());
// 计算总页数
if (result.getTotal() == 0) {
result.setPages(0);
} else {
result.setPages((int) Math.ceil((double) result.getTotal() / result.getPageSize()));
}
// 计算是否有上一页/下一页
result.setHasPrevious(result.getPageNum() > 1);
result.setHasNext(result.getPageNum() < result.getPages());
return result;
}
// getters and setters
public Integer getPageNum() {
return pageNum;
}
public void setPageNum(Integer pageNum) {
this.pageNum = pageNum;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public Long getTotal() {
return total;
}
public void setTotal(Long total) {
this.total = total;
}
public Integer getPages() {
return pages;
}
public void setPages(Integer pages) {
this.pages = pages;
}
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
public Boolean getHasPrevious() {
return hasPrevious;
}
public void setHasPrevious(Boolean hasPrevious) {
this.hasPrevious = hasPrevious;
}
public Boolean getHasNext() {
return hasNext;
}
public void setHasNext(Boolean hasNext) {
this.hasNext = hasNext;
}
}
分页工具类
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 分页工具类
*/
public class PageUtils {
/**
* 手动分页(内存分页)
*/
public static <T> PageResult<T> manualPage(List<T> dataList, PageRequest pageRequest) {
if (dataList == null || dataList.isEmpty()) {
return PageResult.build(Collections.emptyList(), 0L, pageRequest);
}
long total = dataList.size();
int fromIndex = pageRequest.getOffset();
int toIndex = Math.min(fromIndex + pageRequest.getPageSize(), dataList.size());
List<T> pageList;
if (fromIndex >= dataList.size()) {
pageList = Collections.emptyList();
} else {
pageList = dataList.subList(fromIndex, toIndex);
}
return PageResult.build(pageList, total, pageRequest);
}
/**
* 转换分页结果中的数据类型
*/
public static <T, R> PageResult<R> convert(PageResult<T> source, Function<T, R> converter) {
PageResult<R> result = new PageResult<>();
result.setPageNum(source.getPageNum());
result.setPageSize(source.getPageSize());
result.setTotal(source.getTotal());
result.setPages(source.getPages());
result.setHasPrevious(source.getHasPrevious());
result.setHasNext(source.getHasNext());
if (source.getList() != null) {
result.setList(source.getList().stream()
.map(converter)
.collect(Collectors.toList()));
}
return result;
}
}
MyBatis Plus 分页实现
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.stereotype.Service;
/**
* MyBatis Plus 分页示例
*/
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
/**
* 使用MyBatis Plus分页插件
*/
public PageResult<UserVO> pageUsers(PageRequest pageRequest) {
// 创建MyBatis Plus分页对象
Page<User> page = new Page<>(pageRequest.getPageNum(), pageRequest.getPageSize());
// 执行分页查询(自动添加limit)
IPage<User> userPage = userMapper.selectPage(page, null);
// 转换为通用分页结果
List<UserVO> userVOS = userPage.getRecords().stream()
.map(this::convertToVO)
.collect(Collectors.toList());
return PageResult.build(userVOS, userPage.getTotal(), pageRequest);
}
/**
* 带条件的分页查询
*/
public PageResult<UserVO> searchUsers(String keyword, PageRequest pageRequest) {
Page<User> page = new Page<>(pageRequest.getPageNum(), pageRequest.getPageSize());
// 使用Lambda条件构造器
LambdaQueryWrapper<User> wrapper = Wrappers.<User>lambdaQuery()
.like(StringUtils.isNotBlank(keyword), User::getUsername, keyword)
.orderByDesc(User::getCreateTime);
IPage<User> userPage = userMapper.selectPage(page, wrapper);
List<UserVO> userVOS = userPage.getRecords().stream()
.map(this::convertToVO)
.collect(Collectors.toList());
return PageResult.build(userVOS, userPage.getTotal(), pageRequest);
}
}
原生JDBC/MyBatis分页实现
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
/**
* 原生SQL分页查询
*/
@Mapper
public interface ProductMapper {
/**
* 查询总数
*/
@Select("SELECT COUNT(*) FROM product WHERE status = #{status}")
Long countByStatus(@Param("status") Integer status);
/**
* 分页查询
*/
@Select("SELECT * FROM product WHERE status = #{status} " +
"ORDER BY create_time DESC " +
"LIMIT #{offset}, #{pageSize}")
List<Product> pageByStatus(@Param("status") Integer status,
@Param("offset") Integer offset,
@Param("pageSize") Integer pageSize);
}
@Service
public class ProductService {
@Autowired
private ProductMapper productMapper;
/**
* 手动分页实现
*/
public PageResult<Product> pageProducts(Integer status, PageRequest pageRequest) {
// 查询总数
Long total = productMapper.countByStatus(status);
// 查询分页数据
List<Product> list;
if (total > 0) {
list = productMapper.pageByStatus(status,
pageRequest.getOffset(),
pageRequest.getPageSize());
} else {
list = Collections.emptyList();
}
return PageResult.build(list, total, pageRequest);
}
}
Spring Data JPA分页实现
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* JPA Repository
*/
public interface OrderRepository extends JpaRepository<Order, Long>,
JpaSpecificationExecutor<Order> {
}
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
/**
* JPA分页查询
*/
public PageResult<Order> pageOrders(PageRequest pageRequest) {
// 创建JPA分页对象
Sort sort = Sort.by(Sort.Direction.DESC, "createTime");
Pageable pageable = PageRequest.of(
pageRequest.getPageNum() - 1, // JPA页码从0开始
pageRequest.getPageSize(),
sort
);
// 执行分页查询
Page<Order> orderPage = orderRepository.findAll(pageable);
// 转换为通用分页结果
return PageResult.build(
orderPage.getContent(),
orderPage.getTotalElements(),
pageRequest
);
}
/**
* 带条件的分页查询
*/
public PageResult<Order> searchOrders(String orderNo, PageRequest pageRequest) {
Pageable pageable = PageRequest.of(
pageRequest.getPageNum() - 1,
pageRequest.getPageSize()
);
// 使用Specification构建条件
Specification<Order> spec = (root, query, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>();
if (StringUtils.isNotBlank(orderNo)) {
predicates.add(criteriaBuilder.like(root.get("orderNo"), "%" + orderNo + "%"));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
};
Page<Order> orderPage = orderRepository.findAll(spec, pageable);
return PageResult.build(
orderPage.getContent(),
orderPage.getTotalElements(),
pageRequest
);
}
}
使用示例
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
/**
* 分页查询用户列表
*/
@GetMapping("/page")
public Result<PageResult<UserVO>> pageUsers(PageRequest pageRequest) {
PageResult<UserVO> result = userService.pageUsers(pageRequest);
return Result.success(result);
}
/**
* 搜索用户分页
*/
@GetMapping("/search")
public Result<PageResult<UserVO>> searchUsers(
@RequestParam(required = false) String keyword,
PageRequest pageRequest) {
PageResult<UserVO> result = userService.searchUsers(keyword, pageRequest);
return Result.success(result);
}
}
// 通用响应对象
class Result<T> {
private Integer code;
private String message;
private T data;
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage("success");
result.setData(data);
return result;
}
// getters and setters...
}
分页查询最佳实践
前端请求示例
// axios请求
axios.get('/api/users/page', {
params: {
pageNum: 1,
pageSize: 10,
orderBy: 'createTime',
orderType: 'desc'
}
}).then(response => {
console.log(response.data);
});
注意事项
- 防止SQL注入:排序字段需要做白名单校验
- 分页大小限制:设置最大分页大小,防止内存溢出
- 缓存优化:对不经常变化的数据做缓存
- 索引优化:分页查询字段要建立合适的索引
- 大数据量处理:使用游标分页或键集分页代替传统分页
这个通用的分页模块可以适配不同的ORM框架,提供一致的分页功能,你可以根据具体需求选择使用手动分页、MyBatis Plus、JPA等不同实现方式。