Spring Data JPA中使用Specification<T>实现动态查询与分页查询(清晰!)

首先, 定义的Dao接口不仅要继承JpaRepository接口,还有继承JpaSpecificationExecutor接口, 如下:

//JpaRepository 用于简单查询
//JpaSpecificationExecutor 动态拼接sql 用于复杂查询
public interface LabelDao extends JpaRepository<Label,String> ,JpaSpecificationExecutor<Label> {
}

分析源码

按住Ctrl键 点击JpaSpecificationExecutor可以看到

public interface JpaSpecificationExecutor<T> {
    Optional<T> findOne(@Nullable Specification<T> var1);

    List<T> findAll(@Nullable Specification<T> var1);

    Page<T> findAll(@Nullable Specification<T> var1, Pageable var2);

    List<T> findAll(@Nullable Specification<T> var1, Sort var2);

    long count(@Nullable Specification<T> var1);
}

通过方法名我们大体可以知道:

//根据条件查询一个对象
Optional findOne(@Nullable Specification var1);

//根据条件查询集合
List findAll(@Nullable Specification var1);

//根据条件分页查询
Page findAll(@Nullable Specification var1, Pageable var2);

//排序查询查询
List findAll(@Nullable Specification var1, Sort var2);

//统计查询
long count(@Nullable Specification var1);

这时我有点疑惑,Specification是什么,好吧,点进去看一下
再次按住Ctrl键 点击Specification
 

public interface Specification<T> extends Serializable {
    long serialVersionUID = 1L;

    static <T> Specification<T> not(Specification<T> spec) {
        return Specifications.negated(spec);
    }

    static <T> Specification<T> where(Specification<T> spec) {
        return Specifications.where(spec);
    }

    default Specification<T> and(Specification<T> other) {
        return Specifications.composed(this, other, CompositionType.AND);
    }

    default Specification<T> or(Specification<T> other) {
        return Specifications.composed(this, other, CompositionType.OR);
    }

    @Nullable
    Predicate toPredicate(Root<T> var1, CriteriaQuery<?> var2, CriteriaBuilder var3);
}

最后这个方法就是我们动态查询要实现的方法了,分析:

Predicate toPredicate(Root var1, CriteriaQuery<?> var2, CriteriaBuilder var3);

var1: 代表查询的根对象,可以通过 var1获取实体中的属性
var2:代表一个顶层查询对象,用来自定义查询
var3:用于添加查询条件,此对象里有很多条件方法

分析完了,就看怎么写代码来实现动态查询吧

//这里我的前端给我传的是参数是一个map
private Specification<Label> createSpecification(Map map) {

//匿名内部类,实现接口方法
        Specification<Label> spec = new Specification() {
        
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery cq, CriteriaBuilder cb) {
            
            //创建集合,用于存放拼接的条件
                List<Predicate> list = new ArrayList<>();
                
                if(map.get("labelname")!=null&&!"".equals(map.get("labelname"))){
                    Predicate p1 = cb.like(root.get("labelname").as(String.class), "%" + map.get("labelname") + "%");
                    list.add(p1);
                }
                if(map.get("state")!=null&&!"".equals(map.get("state"))){
                    Predicate p2 = cb.equal(root.get("state").as(String.class), map.get("state"));
                    list.add(p2);
                }
                if(map.get("recommend")!=null&&!"".equals(map.get("recommend"))){
                    Predicate p3 = cb.equal(root.get("recommend").as(String.class), map.get("recommend"));
                    list.add(p3);
                }
                return cb.and(list.toArray(new Predicate[list.size()]));
            }
        };
        return spec;
    }

这样就可以轻松实现多条件动态查询 和 多条件动态查询加分页了

//多条件查询
    public List<Label> findSearch(Map map){
        Specification<Label> spec = createSpecification(map);
        return labelDao.findAll(spec);
    }
//多条件加分页查询
    public Page<Label> findSearch(Map map, int page, int size){
        Specification<Label> spec = createSpecification(map);
        Pageable pageable = PageRequest.of(page - 1, size);
        return labelDao.findAll(spec,pageable);
    }

因为sql拼接是共用的代码,我把它分离出来封装成方法,这个肯定一眼就能看出来吧…

 

转载自:https://blog.csdn.net/weixin_43254077/article/details/86596790

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!关于您的问题,您可以使用Spring Data JPA提供的Specification实现条件查询,同时使用Pageable来实现分页查询,具体的实现可以参考以下代码示例: ```java import org.springframework.data.domain.Example; import org.springframework.data.domain.ExampleMatcher; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import java.util.ArrayList; import java.util.List; @Service public interface YourRepository extends JpaRepository<S, Long> { default Page<S> search(S example, int pageNum, int pageSize) { ExampleMatcher matcher = ExampleMatcher.matching() .withMatcher("field1", ExampleMatcher.GenericPropertyMatchers.contains()) .withMatcher("field2", ExampleMatcher.GenericPropertyMatchers.contains()) .withIgnorePaths("id", "field3"); // ignore id and field3 Example<S> exampleFilter = Example.of(example, matcher); Specification<S> spec = new Specification<S>() { @Override public Predicate toPredicate(Root<S> root, CriteriaQuery<?> query, CriteriaBuilder cb) { List<Predicate> predicates = new ArrayList<>(); /* add your filters here */ predicates.add(cb.equal(root.get("field4"), "value1")); predicates.add(cb.like(root.get("field5"), "value2%")); return cb.and(predicates.toArray(new Predicate[predicates.size()])); } }; PageRequest pageRequest = PageRequest.of(pageNum, pageSize); return findAll(spec.and(exampleFilter), pageRequest); } } ``` 其,`S`代表实体类型,`field1`到`field5`代表实体的属性名,`value1`和`value2`代表你要匹配的值,`pageNum`和`pageSize`分别代表页码和每页显示的记录数。 希望这可以帮到您!如果您还有任何问题,请随时联系我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值