Spring Data JPA的Specifications和Querydsl

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);
                }

                //-----多表关联条件对象
                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));
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值