之前写过一篇Spring Data JPA 使用JpaSpecificationExecutor实现多条件查询(分页查询和非分页查询),但是筛选条件都是单一的,并不存在包含关系,例如我传ID[1,2,3],希望找到ID是这里面其中一个的所有记录。这时候就需要使用in。
示例场景:根据项目名称查询人员,但是人员表中只有一个项目ID,也即,首先需要通过项目名称模糊查询到对应的项目ID列表,再通过这个ID列表去筛选人员。
代码:
筛选条件方法,使用in:
private Specification<UserDO> buildWhereClause(List<String> projectIndexCodeList, String username,String userPhone){
return (Root<UserDO> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
List<Predicate> predicatesList = new ArrayList<>();
if(projectIndexCodeList != null){
predicatesList.add(cb.in(root.get("projectIndexCode")).value(projectIndexCodeList));
}
if(StringUtils.isNotBlank(username)){
predicatesList.add(cb.like(cb.lower(root.get("username").as(String.class)),"%" + username.toLowerCase() + "%"));
}
if(StringUtils.isNotBlank(userPhone)){
predicatesList.add(cb.like(root.get("userPhone").as(String.class), userPhone + "%"));
}
Predicate[] andPredicate = new Predicate[predicatesList.size()];
return cb.and(predicatesList.toArray(andPredicate));
};
}
调用:
findByNameLike方法记得在Repository中声明一下,然后注意在使用时需要手动加上%。
然后注意一下 这里的分页起始页码 和返回页码都是0开始的,如果要从1开始,可以在设置Pageable时手动把传进来的参数xxxReqBO.getPageNo()-1,但是此时返回时还是0,所以在返回页码时需要将pageable.getPageNumber()手动+1。
List<String> projectIndexCodeList = null;
//通过项目名找到项目编码
if(StringUtils.isNotEmpty(xxxReqBO.getProjectName())){
List<ProjectDO> projectDOList = projectRepository.findByNameLike("%"+xxxReqBO.getProjectName()+"%");
projectIndexCodeList = projectDOList.stream().map(ProjectDO::getProjectIndexCode).collect(Collectors.toList());
}
//设置筛选条件和分页参数,把项目编码列表塞进去
Specification<xxxPeopleDO> PeopleDOSpecification = buildWhereClause(projectIndexCodeList,xxxReqBO.getUsername(),xxxReqBO.getUserPhone());
Pageable pageable = PageRequest.of(xxxReqBO.getPageNo(), xxxReqBO.getPageSize());
//获取符合条件的DOList
Page<xxxPeopleDO> peopleDOPage = xxxPeopleRepository.findAll(PeopleDOSpecification,pageable);
List<xxxPeopleDO> peopleDOList = peopleDOPage.getContent();
//设置返回参数 总数、页码和每页数量的获取方式前文有写 这里再写一遍
//获取总数: (int) peopleDOPage.getTotalElements(),
//页码和分页大小:pageable.getPageNumber(), pageable.getPageSize()
然后注意,在写筛选条件方法的时候其实是有一个坑的,注意我这里的写法
if(projectIndexCodeList != null){
predicatesList.add(cb.in(root.get("projectIndexCode")).value(projectIndexCodeList));
}
为什么判定条件用projectIndexCodeList!=null
?此时list为null时视为不过滤;但不为null,size为0时视为不满足条件。
刚开始的时候出于习惯,我用的是CollectionUtils.isNotEmpty(projectIndexCodeList)
,后果是筛选条件失效。失效的原因是,在通过名称找ID未找到时,此时正常而言应该不返回数据,但此时projectIndexCodeList为空(而不是null),直接没有进入这个判断,因此跳过了该筛选条件。
那既然这样,直接不判断了行吗?也不行,因为在筛选条件未传入项目编码时,希望不进行筛选。