如何在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:
- 首先让Repository继承
JpaSpecificationExecutor:
public interface PostRepository extends CrudRepository<Post, Long>, JpaSpecificationExecutor<Post> { }
- 编写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) ); }; } }
- 在Service中调用:
public Page<Post> searchPosts(String keyword, Pageable pageable) { Specification<Post> spec = PostSpecifications.titleOrContentContainsWildcard(keyword); return postRepository.findAll(spec, pageable); }
方案三:自定义Repository实现类
如果需要处理更复杂的通配符逻辑(比如支持?匹配单个字符),可以自定义Repository的实现类:
- 定义自定义Repository接口:
public interface PostRepository extends CrudRepository<Post, Long>, PostRepositoryCustom { } public interface PostRepositoryCustom { Page<Post> searchWithWildcard(String keyword, Pageable pageable); }
- 编写实现类(注意类名要以
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
相关产品推荐
相关产品推荐

