要想使用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的開源項目也提供了類似的解決方案,但是實現有所不同,提供了更有好的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));新聞熱點
疑難解答