您的位置:首页 > 编程语言 > Java开发

Spring Data JPA的Specifications和Querydsl

2017-02-20 18:12 615 查看

Specifications

要想使用Specifications,必须继承JpaSpecificationExecutor接口。该接口扩展了查询方法findAll:

条件不分页:List findAll(Specification spec);

条件+分页:Page findAll(Specification spec, Pageable pageable);

Specification接口:

public interface Specification<T> {
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
}


Demo1代码:

@Action("subarea_listPage")
public String listPage() throws Exception{
//Spring Data实现QBC方式查询
//需要两个参数对象:Specification(条件规范)和Pageable(分页规范)
//1.------分页对象
Pageable pageable = new PageRequest(page-1, rows);
//2.-------条件对象
Specification<Subarea> specification = new Specification<Subarea>() {
//参数1:Root:根对象(要查询的主实体对象)
//参数2:CriteriaQuery:条件查询对象
//参数3:CriteriaBuilder:条件查询的构建对象,类似于criteria编程方式
//返回:Predicate:where后面的条件包装对象
@Override
public Predicate toPredicate(Root<Subarea> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//定义条件对象列表
List<Predicate> pList = new ArrayList<>();
//单表条件对象构建(定区编码和地区关键字在分区表中)

//地区关键字条件
if (StringUtils.isNotBlank(model.getAddresskey())) {
//参数1:条件表达式
//参数2:值
Predicate p1 = cb.equal(root.get("addresskey"), model.getAddresskey());
pList.add(p1);
}

//定区关键字条件
if (model.getDecidedZone() != null && StringUtils.isNotBlank(model.getDecidedZone().getId())) {
//参数1:条件表达式
//参数2:值
Predicate p2 = cb.equal(root.get("decidedZone").as(DecidedZone.class), model.getDecidedZone());
pList.add(p2);
}

//-----多表关联条件对象
4000

if (model.getRegion() != null) {
//获取连接实体对象
//参数1:连接的目标对象;参数2:多表连接的类型
Join<Subarea, Region> regionJoin = root.join(root.getModel().getSingularAttribute("region",Region.class),JoinType.INNER);
//要连接的实体条件构建

//省份条件
if (model.getRegion() != null && StringUtils.isNotBlank(model.getRegion().getProvince())) {
Predicate p3 = cb.like(regionJoin.get("province").as(String.class), "%"+model.getRegion().getProvince()+"%");
pList.add(p3);
}

//城市条件
if (model.getRegion() != null && StringUtils.isNotBlank(model.getRegion().getCity())) {
Predicate p4 = cb.like(regionJoin.get("city").as(String.class), "%"+model.getRegion().getCity()+"%");
pList.add(p4);
}

//区域条件
if (model.getRegion() != null && StringUtils.isNotBlank(model.getRegion().getDistrict())) {
Predicate p5 = cb.like(regionJoin.get("district").as(String.class), "%"+model.getRegion().getDistrict()+"%");
pList.add(p5);
}

}
//pList转换为具体类型的数组
Predicate[] predicate = pList.toArray(new Predicate[0]);

//将条件进行汇总并返回
return cb.and(predicate);
}
};

//调用servic进行查询
Page<Subarea> pageResponse = subareaService.findSubareaListPage(specification,pageable);
//将结果转换为map格式
Map<String,Object> resultMap = new HashMap<String,Object>();
resultMap.put("total", pageResponse.getTotalElements());
resultMap.put("rows", pageResponse.getContent());
//将结果压入栈顶
pushToValueStack(resultMap);
//返回json类型
return JSON;
}


Demo2代码:

@Action("decidedzone_listPage")
public String decidedzone_listPage() throws Exception{
//分页数据
Pageable pageable = new PageRequest(page-1, rows);
//业务条件
Specification<DecidedZone> specification =new Specification<DecidedZone>(){
@Override
public Predicate toPredicate(Root<DecidedZone> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//条件表达式集合
Predicate predicateAnd = cb.conjunction();//交集
Predicate predicateOr = cb.disjunction();//并集
//定区编码条件
if (StringUtils.isNotBlank(model.getId())) {
predicateAnd.getExpressions().add(cb.equal(root.get("id").as(String.class), model.getId()));
}
//所属单位
if (model.getStaff() != null) {
//多表关联
root.join(root.getModel().getSingularAttribute("staff",Staff.class),JoinType.LEFT);
//根据取派员的单位作为条件
if (StringUtils.isNotBlank(model.getStaff().getStation())) {
predicateAnd.getExpressions().add(cb.like(root.get("station").as(String.class), "%"+model.getStaff().getStation()+"%"));
}
}
//是否关联分区
if (StringUtils.isNotBlank(hasSubarea)) {
if (hasSubarea.equals("1")) {
predicateAnd.getExpressions().add(cb.isNotEmpty(root.get("subareas").as(Set.class)));
} else {
predicateAnd.getExpressions().add(cb.isEmpty(root.get("subareas").as(Set.class)));
}
}
return predicateAnd;
}

};
//调用service进行查询
Page<DecidedZone> pageResponse = decidedZoneService.findDecidedZoneListPage(pageable,specification);
//结果map
Map<String,Object> resultMap = new HashMap<String,Object>();
resultMap.put("total", pageResponse.getTotalElements());
resultMap.put("rows", pageResponse.getContent());
//把结果压入栈顶
pushToValueStack(resultMap);
//返回json类型
return JSON;
}


Querydsl

Querydsl的开源项目也提供了类似的解决方案,但是实现有所不同,提供了更有好的API,而且不仅支持JPA,还支持hibernate,JDO,Lucene,JDBC甚至是原始集合的查询。

为了使用Querydsl,需要在pom.xml中引入依赖并且配置一个额外的APT插件。

<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>maven-apt-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources</outputDirectory>
<processor>com.mysema.query.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>


BooleanExpressions还可以直接重用,免去使用更多包装方法的写法,要执行查询,跟Specification类似,让repository继承QueryDslPredicateExecutor接口即可。

public interface CustomerRepository extends JpaRepository<Customer>, QueryDslPredicateExecutor {
// Your query methods here
}

QCustomer customer = QCustomer.customer;
LocalDate today = new LocalDate();
BooleanExpression customerHasBirthday = customer.birthday.eq(today);
BooleanExpression isLongTermCustomer = customer.createdAt.lt(today.minusYears(2));
customerRepository.findAll(customerHasBirthday.and(isLongTermCustomer));
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: