首先, 定义的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