暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

SpringBoot之JPA复杂查询

DevHome 2020-06-02
1778
一、前言
上篇文章提到了在SpringBoot中使用JPA的案例:方式为首先创建一个Repository接口然后继承JpaRepository 接口就可以实现日常开发的常用增删改查功能,其次在该接口中也可以按照JPA方法命名规范定义查询方法,由JPA方法解析并生成相应的SQL去数据库执行对应功能。但是项目中我们发现有些复杂的多条件分页查询,这些简单的方法是无法满足的。比如一个商品的多条件搜索,由于搜索条件是动态变化的,使用固定参数的简单方法是无法实现的,这时候我们应该如何操作呢?今天我们就来看一看:

二、JPA多条件查询

我们依然使用昨天的Repository 但是仅仅继承JpaRepository是不够的,若要完成复杂查询则需要继承JpaSpecification<Person>  “<>”里面存放的是该接口需要操作的实体类对象,我们仍以昨天的Person类对象为例。

@Repository
public interface PersonRepository extends JpaRepository<Person,Long>, JpaSpecificationExecutor<Person> {
}
复制

实现的步骤首先是创建一个specification 对象,然后实现里面的toPredicate()方法,然后可以使用if语句动态的构建查询参数,前端传入相应的参数,就拼接对应的查询语句,该字段为null则不拼接对应的查询语句,非常的方便灵活。拼接好相应的查询语句后,再利用and连接构建一个predicate 对象。最后传入specification、pageable等参数,使用repository已经帮我们实现的findAll(specification, pageable)方法实现分页(排序)的多条件查询。该方法将返回一个page对象,里面包含了分页数据以及分页信息。

构建查询语句时,其中的api设计和SQL本来的原意很相近,容易理解。具体相关的api都以注释的形式放在代码中。这些非常直观的api可以帮助我们拼接成丰富多彩的查询语句,避免我们手动去写原生的SQL语句。

 /**
* todo spring data jpa 使用specification 进行查询 3-11
* 十分实用和好用
*
* @param query
* @return
*/
public Page<Person> queryPersonsByLamdaConditions(PersonQuery query) {
// List<Sort.Order> orders = new ArrayList<>();
// Sort.Order order1= new Sort.Order(Sort.Direction.ASC,"createTime");
// Sort.Order order2= new Sort.Order(Sort.Direction.ASC,"personType");
// orders.add(order2);
// orders.add(order1);
// new Sort(orders)
// 多个字段进行排序
Sort sort = new Sort(Sort.Direction.DESC, "personType").
and(new Sort(Sort.Direction.ASC, "createTime"));


Pageable pageable = PageRequest.of(query.getPage() - 1, query.getPageSize(), sort);
// 先创建一个说明书, 借助这个说明书进行查询
Specification<Person> specification = new Specification<Person>() {
@Override
public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
// 然后再创建一个查询预测条件的数组
List<Predicate> list = new ArrayList<>();
// 模糊查询 like
if (StringUtils.isNotBlank(query.getUserName())) {
list.add(criteriaBuilder.like(root.get("userName"), query.getUserName()));
}
// 等于 equal
if (query.getAge() != null) {
list.add(criteriaBuilder.equal(root.get("age"), query.getAge()));
}
// where in list集合
if (CollectionUtils.isNotEmpty(query.getUnitIds())) {
list.add(criteriaBuilder.in(root.get("unitId")).value(query.getUnitIds()));
}
if (Objects.nonNull(query.getCreateTime())) {
// 大于等于
// list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), query.getCreateTime()));
// 大于
// list.add(criteriaBuilder.greaterThan(root.get("createTime"), query.getCreateTime()));
// 小于等于
// list.add(criteriaBuilder.lessThanOrEqualTo(root.get("createTime"), query.getCreateTime()));
// 小于
list.add(criteriaBuilder.lessThan(root.get("createTime"), query.getCreateTime()));
}
// 介于二者之间的
if (Objects.nonNull(query.getStartTime()) && Objects.nonNull(query.getEndTime())) {
list.add(criteriaBuilder.between(root.get("createTime"), query.getStartTime(), query.getEndTime()));
}


Predicate[] predicates = new Predicate[list.size()];
// 将其转换成predicate数组
return criteriaBuilder.and(list.toArray(predicates));
}
};


Page<Person> page = personRepository.findAll(specification, pageable);
List<Person> personEntities = page.getContent();
// 此处可以将 personEntities 可以再转换为vo
// List<PersonVo> personVoList = MapperUtil.mapperObjectList(PersonVo.class, personEntities);
// 再新构建一个page页面
return new PageImpl<>(personEntities, pageable, page.getTotalElements());
}
复制

三、小结

面对一些多条件复杂查询,JPA内置方法以及通过方法名构建的简单方法已经不能满足我们的需求,这时候需要在repository中继承JpaSpecificationExecutor接口,然后创建一个specification对象和pageable对象,调用findAll(specification,pageable)方法完成多条件的查询任务。



文章转载自DevHome,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论