public interface JpaSpecificationExecutor {
T findOne(Specification spec);//根据sql获取单个对象数据
List findAll(Specification spec);//根据sql查询所有数据
Page findAll(Specification spec, Pageable pageable);//根据sql分页查询数据
List findAll(Specification spec, Sort sort); //根据sql查询数据,并根据参数进行排序
long count(Specification spec); //根据sql查询数据总数
}
//可以输入多个Sort.Order对象,在进行多个值排序时有用
public Sort(Sort.Order... orders);
//和上面的方法一样,无非把多个参数换成了一个List
public Sort(List orders);
//当排序方向固定时,使用这个比较方便,第一个参数是排序方向,第二个开始就是排序的字段.
public Sort(Sort.Direction direction, String... properties);
//第一个参数是排序方向,还有一个方法第二个参数是list,原理相同
public Sort(Direction direction, List properties);
int getPageNumber();
int getPageSize();
int getOffset();
Sort getSort();
Pageable next();
Pageable previousOrFirst();
Pageable first();
boolean hasPrevious();
//这个构造方法构造出来的分页对象不具备排序功能
public PageRequest(int page, int size) {
this(page, size, (Sort)null);
}
//Direction和properties用来做排序操作
public PageRequest(int page, int size, Direction direction, String... properties) {
this(page, size, new Sort(direction, properties));
}
//此构造方法是自定义一个排序的操作
public PageRequest(int page, int size, Sort sort) {
super(page, size);
this.sort = sort;
}
Spring Data Jpa 支持 Criteria 查询方式,使用这种方式需要继承JpaSpecificationExecutor,通过实现 Specification
中的 toPredicate方法来定义动态查询,通过 CriteriaBuilder 来创建查询条件
Specification specification = new Specification(){
@Override
public Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder cb){
List predicates = new ArrayList();
//root.get("name")表示获取name这个字段名称,like表示执行like查询,%zt%表示值
Predicate p1 = cb.like(root.get("name"), "%ray%");
Predicate p2 = cb.greaterThan(root.get("rid"),"3");
//将两个查询条件联合起来之后返回Predicate对象
//建立子查询
//构建criteriaQuery对象
CriteriaQuery criteriaQuery = cb.createQuery(Organization.class);
//获取子查询Subquery对象
Subquery organizationSubQuery = criteriaQuery.subquery(Organization.class);
//构建新的子查询字段Mapping对象
Root organizationSubRoot = organizationubQuery.from(Organization.class);
//相当于sql中的select *,如需获取一个字段可以使用organizationSubRoot.get("字段").as(String.class).
organizationSubQuery.select(organizationSubRoot);
Predicate subqueryPredicate = cb.and(cb.equal(organizationSubRoot .get("rid").as(String.class), root.get("rid").as(String.class),
cb.equal(organizationSubRoot .get("orgName").as(String.class),"部门名称"));
//构建where条件
organizationSubQuery .where(subqueryPredicate);
// exists的使用
Predicate p3 = cb.exists(organizationSubQuery);
//相当于select rid,name...
query.multiselect(root.get("rid"),root.get("name"));
Predicate p4 = cb.and(p1,p2,p3);
predicates.add(p4)
return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
}
};
利用JpaSpecificationExecutor的findAl方法进行分页查询,例子如下:
Order order = new Order(Direction.ASC,"name");
Sort sort = new Sort(order);
Pageable pageable = new PageRequest(page,size,sort);//page从0开始
Page resutls = UserDao.findAll(specification, pageable);
PS:其中UserDao需要继承JpaSpecificationExecutor和Repository接口。
其实也可以定义多个 Specification,然后通过 Specifications 对象将其连接起来,复杂sql可以这样做,使代码不会这么臃肿。
//第一个Specification定义了两个or的组合
Specification s1 = new Specification() {
@Override
public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
Predicate p1 = criteriaBuilder.equal(root.get("rid"),"2");
Predicate p2 = criteriaBuilder.equal(root.get("rid"),"3");
return criteriaBuilder.or(p1,p2);
}
};
//第二个Specification定义了两个or的组合
Specification s2 = new Specification() {
@Override
public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
Predicate p1 = criteriaBuilder.like(root.get("name"),"r%");
Predicate p2 = criteriaBuilder.like(root.get("name"),"a%");
return criteriaBuilder.or(p1,p2);
}
};
//通过Specifications将两个Specification连接起来,第一个条件加where,第二个是and
List userList= UserDao.findAll(Specifications.where(s1).and(s2));
这个代码生成的 SQL 是
select * from t_user where (rid='2' or rid='3') and (name like 'r%' or name like 'a%');
•toPredicate 中还有 CriteriaQuery 参数,这个对象提供了更多有用的查询,如分组之类的查询,这里就不一一列举了,可以参考:http://www.objectdb.com/java/jpa/query/jpql/structure