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

如何在Spring JPA/CrudRepository中结合分页使用通配符查询?

Spring JPA 实现带自定义通配符的分页搜索方案

你提到的方法签名方式确实无法直接处理自定义通配符(因为Spring Data JPA的Containing系列方法会自动对参数中的%和_进行转义),以下是几种结合Pageable的可行方案:

方案一:使用@Query注解自定义JPQL查询

直接通过JPQL手动处理通配符替换,同时实现忽略大小写和分页:

public interface PostRepository extends CrudRepository<Post, Long> {

    @Query("SELECT p FROM Post p WHERE " +
           "(LOWER(p.title) LIKE LOWER(CONCAT('%', REPLACE(:keyword, '*', '%'), '%'))) OR " +
           "(LOWER(p.content) LIKE LOWER(CONCAT('%', REPLACE(:keyword, '*', '%'), '%'))) " +
           "ORDER BY p.title ASC")
    Page<Post> searchByTitleOrContentWithWildcard(@Param("keyword") String keyword, Pageable pageable);
}

调用时直接传入前端的Chicken*Potato即可,JPQL中的REPLACE函数会自动将*替换为%,LOWER函数实现忽略大小写匹配,同时Pageable参数负责分页逻辑。

方案二:使用Specification动态构建查询

如果需要更灵活的查询扩展(比如后续新增过滤条件),可以用Specification结合JpaSpecificationExecutor:

  1. 首先让Repository继承JpaSpecificationExecutor:
public interface PostRepository extends CrudRepository<Post, Long>, JpaSpecificationExecutor<Post> {
}
  1. 编写Specification工具方法处理通配符:
public class PostSpecifications {
    public static Specification<Post> titleOrContentContainsWildcard(String keyword) {
        // 替换*为%,并前后添加%实现模糊匹配
        String processedKeyword = "%" + keyword.replace("*", "%") + "%";
        String lowerKeyword = processedKeyword.toLowerCase();

        return (root, query, criteriaBuilder) -> {
            Expression<String> titleLower = criteriaBuilder.lower(root.get("title"));
            Expression<String> contentLower = criteriaBuilder.lower(root.get("content"));
            return criteriaBuilder.or(
                criteriaBuilder.like(titleLower, lowerKeyword),
                criteriaBuilder.like(contentLower, lowerKeyword)
            );
        };
    }
}
  1. 在Service中调用:
public Page<Post> searchPosts(String keyword, Pageable pageable) {
    Specification<Post> spec = PostSpecifications.titleOrContentContainsWildcard(keyword);
    return postRepository.findAll(spec, pageable);
}

方案三:自定义Repository实现类

如果需要处理更复杂的通配符逻辑(比如支持?匹配单个字符),可以自定义Repository的实现类:

  1. 定义自定义Repository接口:
public interface PostRepository extends CrudRepository<Post, Long>, PostRepositoryCustom {
}

public interface PostRepositoryCustom {
    Page<Post> searchWithWildcard(String keyword, Pageable pageable);
}
  1. 编写实现类(注意类名要以Impl结尾,Spring Data会自动识别):
@Repository
public class PostRepositoryImpl implements PostRepositoryCustom {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public Page<Post> searchWithWildcard(String keyword, Pageable pageable) {
        String processedKeyword = "%" + keyword.replace("*", "%").replace("?", "_") + "%";
        String lowerKeyword = processedKeyword.toLowerCase();

        // 查询结果列表
        String jpql = "SELECT p FROM Post p WHERE LOWER(p.title) LIKE :keyword OR LOWER(p.content) LIKE :keyword ORDER BY p.title ASC";
        TypedQuery<Post> query = entityManager.createQuery(jpql, Post.class)
                .setParameter("keyword", lowerKeyword)
                .setFirstResult((int) pageable.getOffset())
                .setMaxResults(pageable.getPageSize());

        // 查询总条数
        String countJpql = "SELECT COUNT(p) FROM Post p WHERE LOWER(p.title) LIKE :keyword OR LOWER(p.content) LIKE :keyword";
        Long total = entityManager.createQuery(countJpql, Long.class)
                .setParameter("keyword", lowerKeyword)
                .getSingleResult();

        return new PageImpl<>(query.getResultList(), pageable, total);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 00:13:28