Spring Data JPA 使用JpaSpecificationExecutor实现多条件查询(分页查询和非分页查询)

本文详细介绍如何在Spring Data JPA中使用JpaSpecificationExecutor实现复杂条件查询,包括非分页和分页查询,以及如何在Service层设置筛选条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、Repository层继承JpaSpecificationExecutor<T>

如下:

@Repository
public interface UserRepository extends JpaRepository<UserDO,Long>, JpaSpecificationExecutor<UserDO> {

}

UserDO:

import lombok.Data;
import javax.persistence.*;

@Data
@Entity
@Table(name = "table_user")
public class UserDO {
	@Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "username")
    private String username;

    @Column(name = "user_phone")
    private String userPhone;

}

说明:
JpaSpecificationExecutor 实现了多条件查询,有如下几个已定义的接口:
1、获取单个对象数据
2、根据筛选条件查询所有数据
3、根据筛选条件分页查询所有数据
4、根据筛选条件查询所有数据并根据参数进行排序
5、根据筛选条件查询数据总数

public interface JpaSpecificationExecutor<T> {

    Optional<T> findOne(@Nullable Specification<T> var1);

    List<T> findAll(@Nullable Specification<T> var1);

    Page<T> findAll(@Nullable Specification<T> var1, Pageable var2);

    List<T> findAll(@Nullable Specification<T> var1, Sort var2);

    long count(@Nullable Specification<T> var1);
}

2、Service层编写方法设置筛选条件Specification

示例:根据用户名和电话号码进行筛选:
可以进行模糊查询和大小写设置

private Specification<UserDO> buildWhereClause(String username,String userPhone){
        return (Root<UserDO> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {

            List<Predicate> predicatesList = new ArrayList<>();
            //和 != null有什么区别?和isNotEmpty呢?
            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));
        };
    }

CriteriaBuilder除了这里的模糊查询like方法之外,还有如下方法:
equal:相等;gt:filed > value;lt:小于;ge:大于等于;le:小于等于;
notLike;notEqual

3、在Service层调用刚刚编写的方法和Repository层的方法实现查询

①非分页查询

	@Override
    public List<UserBO> findByConditions(UserBO userBO) {

        //调用buildWhereClause获取列表
        Specification<UserDO> userDOSpecification = buildWhereClause(userBO.getUsername(),userBO.getUserPhone());
        List<UserDO> userDOList = userRepository.findAll(userDOSpecification);
		//遍历UserDO转为UserBO再对userBOList进行返回即可,不写了
        return null;
    }

②分页查询

其实只是多加了一个参数page,然后返回参数不同,涉及到怎么把page里面的UserDO拿出来并转为UserBO的问题。

	public xxxRespBO findPageByConditions(UserBO userBO, Pageable page){
        Specification<UserDO> userDOSpecification = buildWhereClause(userBO.getUsername(),userBO.getUserPhone());
        Page<UserDO> userDOPage = userRepository.findAll(userDOSpecification,page);
        //通过.getContent();拿到list
        List<UserDO> userDOS = userDOPage.getContent();
        return null;
    }

拿到List之后就容易了,遍历再进行赋值即可获得userBOList,再通过userDOPage.getTotalElements();userDOPage.getTotalPages();可以获取到总页数和总记录数;通过pageable.getPageNumber(); pageable.getPageSize();可以获取前端传的页码和每页记录数。
把userBOList和这些七七八八的数据一起放到userRespBO中封装起来传到上一层,再把userBOList转成需要的格式的List,再封装起来(RespDTO)传给前端。

上层调用示例:示例中的1和10由前端传入

xxxRespBO xxx = findPageByConditions(userBO, new PageRequest(1, 10));

当然其实也可以直接findPageByConditions(xxreqBO),(也即页码和页数直接封装在xxreqBO中)这样的话findPageByConditions方法中少了一个pageable参数,可以在该方法中通过如下方法获得:

Pageable pageable = PageRequest.of(从xxreqBO中获取到的页码参数, 每页记录参数);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值