Spring Data JPA的Specifications和Querydsl

来源:互联网 发布:淘宝中国造 编辑:程序博客网 时间:2024/05/19 16:27

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 0
原创粉丝点击