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

具体的可以去查看
https://www.jianshu.com/p/0939cec7e207

上面这段代码我是直接从项目中copy过来的,可以看到这里还使用PageRequest进行了分页,推荐使用PageUtil去构造PageRequest,因为发现直接new的PageRequest的页码是从0开始的,简直反人类- -

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值