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));
相关文章推荐
- Spring Data JPA进阶-Specifications和Querydsl
- 如何在Spring Data JPA中引入Querydsl
- SpringDataJPA学习记录(四)--使用QueryDSL
- Spring data JPA中使用Specifications动态构建查询
- Spring data JPA中使用Specifications动态构建查询
- Spring Data JPA简单学习
- Spring data jpa 多表查询(二:多表动态条件查询)
- Spring Data JPA 入门Demo
- spring data jpa save问题
- Spring data jpa 多表查询(三:多对多关系动态条件查询)
- spring data jpa使用
- Spring Data JPA 实现多表关联查询的示例代码
- spring data jpa javax.el.PropertyNotFoundException
- IBatis Mapper&Spring Data JPA实现原理
- 【系统学习SpringBoot】再遇Spring Data JPA之JPA应用详解(自定义查询及复杂查询)
- 玩转spring MVC(九)---Spring Data JPA
- spring data jpa
- 了解 Spring Data JPA
- Spring data jpa 自定义SQL语句遇到错误Not supported for DML operations