1. 程式人生 > >SpringData jpa 實現多條件動態查詢,分頁功能

SpringData jpa 實現多條件動態查詢,分頁功能

問題由來:

剛開始使用springdata的時候,只會用findByName這樣的簡單查詢,這樣寫dao層確實非常的快,但是在我們做篩選功能的時候,這樣的查詢似乎很難滿足我們的需求,但是都已經用上的springdata又不想再去寫mybatis這樣在xml裡面判斷是否為Null。

解決方案:

1.

Example,用example可以最快速的完成支援所有引數的篩選功能,像這樣的程式碼:

@Test
public void contextLoads() {
    User user = new User();
    user.setUsername("y");
    user.setAddress("sh");
    user.setPassword("admin");
    ExampleMatcher matcher = ExampleMatcher.matching()
            .withMatcher("username", ExampleMatcher.GenericPropertyMatchers.startsWith())//模糊查詢匹配開頭,即{username}%
            .withMatcher("address" ,ExampleMatcher.GenericPropertyMatchers.contains())//全部模糊查詢,即%{address}%
            .withIgnorePaths("password")//忽略欄位,即不管password是什麼值都不加入查詢條件
            .withIgnorePaths("id");  //忽略屬性:是否關注。因為是基本型別,需要忽略掉
    Example<User> example = Example.of(user ,matcher);
    List<User> list = userRepository.findAll(example);
    System.out.println(list);
}

Example會將為null的欄位自動過濾掉,不會作為篩選條件,ExampleMatch是為了支援一些稍微複雜一些的查詢,比如如果有int型別的id就需要用.withIgnorePaths()忽略掉,因為Int型別預設為0,而不是Null。
如果只是簡單的字串匹配的話,可以直接用:

  Example<User> example = Example.of(user);

來構造Example。

但是使用這種方式會遇到一個問題,它沒有辦法實現 id > startId && id < endId 這樣的操作

2.

使用@Query註解,這種方式可以直接在Repository裡面寫sql,但是這種方式的問題就是太麻煩了,而且非常容易出錯,擴充套件性也很差,還不如直接用mybatis。

3.

使用Criteria查詢,這是springdata中最強的使用方式了,所有的場景應該都能完成。
首先Repository要繼承JpaSpecificationExecutor;

public interface UserRepository extends JpaRepository<UpgradeScheduleView,Integer>, JpaSpecificationExecutor {
}

然後就是構造動態查詢:

public Page<UpgradeScheduleView> getPageUpgradeScheduleView(UpgradeViewSelector upgradeViewSelector, int pageNumber, int pageSize) {
        Specification querySpeci = new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = Lists.newArrayList();
                if(!StringUtils.isEmpty(upgradeViewSelector.getTaskName())) {
                    predicates.add(criteriaBuilder
                            .like(root.get("taskName"), "%" + upgradeViewSelector.getTaskName() + "%"));
                }
                if(!StringUtils.isEmpty(upgradeViewSelector.getTboxId())){
                    predicates.add(criteriaBuilder
                            .like(root.get("tboxId"), "%" + upgradeViewSelector.getTboxId() + "%"));
                }
                if(null != upgradeViewSelector.getOver()){
                    predicates.add(criteriaBuilder.equal(root.get("over"), upgradeViewSelector.getOver()));
                }
                if(null != upgradeViewSelector.getFlag()){
                    predicates.add(criteriaBuilder.equal(root.get("flag"), upgradeViewSelector.getFlag()));
                }
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
        PageRequest pageRequest = PageUtil.buildPageRequest(pageNumber, pageSize);
        return upgradeScheduleViewRepository.findAll(querySpeci,pageRequest);
    }

上面這段程式碼我是直接從專案中copy過來的,可以看到這裡還使用PageRequest進行了分頁,推薦使用PageUtil去構造PageRequest,因為發現直接new的PageRequest的頁碼是從0開始的,簡直反人類- -