You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带筛选功能的分页服务实现失败,附代码寻求解决方案

问题排查与解决方案

核心问题点

1. 动态字段参数绑定错误(筛选完全失效)

原生SQL中,:sortField会被Spring Data JPA当作字符串参数处理,而非数据库字段名。实际执行的SQL会变成:

SELECT * FROM HISTORY_BANK WHERE '字段名' LIKE '%xxx%' ...

这是在判断字符串字面量(比如'name')是否匹配筛选关键词,而非对应字段的实际值,导致筛选条件无效,直接返回全表数据。

2. 动态排序语法错误

:sortField和:sortOrder作为字符串参数代入后,ORDER BY子句会变成:

ORDER BY '字段名' 'ASC'

不符合SQL语法规范,数据库无法正确解析排序规则,导致排序失效或直接报错。

3. 统计查询未关联筛选条件

countQuery直接查询全表总数,不包含筛选逻辑,导致分页组件的总页数、总条数都是全表数据,和实际筛选后的结果集完全不匹配。

4. 页码兼容性潜在问题

PageRequest.of(page, size)的页码是从0开始计数,如果前端传入的页码是从1开始(多数前端分页组件默认第一页为1),会导致分页数据偏移,出现第一页为空或数据错位的情况。


修复方案

方案一:使用Spring Data JPA Specification(推荐,无SQL注入风险)

通过动态构建查询条件和排序规则,避免直接拼接SQL:

Repository层修改

public interface HistoryBankRepository extends JpaRepository<HistoryBank, Long>, JpaSpecificationExecutor<HistoryBank> {
}

Service层修改

public PaginationList<HistoryBankWrapper, HistoryBank> findByFilter(String keyfilter, String sortField, String sortOrder, int page, int size) {
    // 构建筛选条件
    Specification<HistoryBank> spec = (root, query, cb) -> {
        if (StringUtils.isBlank(keyfilter)) {
            return cb.conjunction(); // 无筛选条件时返回全部数据
        }
        // 匹配指定字段的内容
        return cb.like(root.get(sortField), "%" + keyfilter + "%");
    };

    // 构建排序规则
    Sort sort = Sort.by(Sort.Direction.fromString(sortOrder), sortField);
    // 若前端页码从1开始,需转换为0开始:PageRequest.of(page - 1, size, sort)
    Pageable paging = PageRequest.of(page, size, sort);

    Page<HistoryBank> historyPage = historyBankRepository.findAll(spec, paging);
    List<HistoryBank> historyList = historyPage.getContent();
    List<HistoryBankWrapper> historyWrapperList = toWrapperList(historyList);
    return new PaginationList<>(historyWrapperList, historyPage);
}

方案二:修正原生SQL(需防范SQL注入)

如果坚持使用原生SQL,需用SPEL表达式动态插入字段名,同时同步countQuery的筛选逻辑:

Repository层修改

@Query(value = "SELECT * FROM HISTORY_BANK WHERE #{#sortField} LIKE '%' || :keyFilter || '%' ORDER BY #{#sortField} #{#sortOrder}",
       countQuery = "SELECT count(*) FROM HISTORY_BANK WHERE #{#sortField} LIKE '%' || :keyFilter || '%'",
       nativeQuery = true)
Page<HistoryBank> findAllFilter(@Param("keyFilter") String keyfilter, 
                                @Param("sortOrder") String sortOrder,
                                @Param("sortField") String sortField, 
                                Pageable paging);

注意:此方式存在SQL注入风险,必须在Service层对sortField做白名单校验(比如限制只能传入数据库已存在的字段名),拦截恶意输入。

额外适配:页码转换

如果前端传入的页码从1开始,Service层需要转换为JPA要求的0起始页码:

Pageable paging = PageRequest.of(page - 1, size, sort);

内容的提问来源于stack exchange,提问作者Juan Kalyzta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 14:05:16