Java分页模块案例如何通用

wen java案例 27

本文目录导读:

Java分页模块案例如何通用

  1. 通用分页请求对象
  2. 通用分页响应对象
  3. 分页工具类
  4. MyBatis Plus 分页实现
  5. 原生JDBC/MyBatis分页实现
  6. Spring Data JPA分页实现
  7. 使用示例
  8. 分页查询最佳实践

我来给你分享一个通用的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);
});

注意事项

  1. 防止SQL注入:排序字段需要做白名单校验
  2. 分页大小限制:设置最大分页大小,防止内存溢出
  3. 缓存优化:对不经常变化的数据做缓存
  4. 索引优化:分页查询字段要建立合适的索引
  5. 大数据量处理:使用游标分页或键集分页代替传统分页

这个通用的分页模块可以适配不同的ORM框架,提供一致的分页功能,你可以根据具体需求选择使用手动分页、MyBatis Plus、JPA等不同实现方式。

抱歉,评论功能暂时关闭!