SpringJPA 做分页条件查询的代码实践
作者:大魔王的日常Log
前言:
相信小伙伴们的项目很多都用到SpringJPA框架的吧,对于单表的增删改查利用jpa是很方便的,但是对于条件查询并且分页 是不是很多小伙伴不经常写到. 今天我整理了一下在这里分享一下.
话不多说直接上代码:
Controller:
@RestController public class ProductInstanceController { @Autowired private ProductInstanceService productInstanceService; @PostMapping("page-find-instance") public PageInfoVO<ProductInst> pageFindInstance(@RequestBody ProductInstParams productInstParams) { return productInstanceService.pageFindInstance(productInstParams); } }
Service:
@Service public class ProductInstanceService { @Autowired private ProductInstRepository productInstRepository; public PageInfoVO<ProductInst> pageFindInstance(ProductInstParams productInstParams) { Sort.Direction direction = Sort.Direction.DESC; //创建一个Pageable对象,其中包含了请求的页码(productInstParams.getPageNo()),每页大小(productInstParams.getPageSize()),排序规则以及排序字段名。 Pageable pageable = PageRequest.of(productInstParams.getPageNo(), productInstParams.getPageSize(), direction, "createdTime"); //将传入的字符串类型的开始日期(startDate)和结束日期(endDate)转换成Date类型 Date start = DateUtil.parseUTC(productInstParams.getStartDate()); Date end = DateUtil.parseUTC(productInstParams.getEndDate()); //执行JPA分页查询: Page<ProductInst> productInstPage = productInstRepository.findAll((root, query, criteriaBuilder) -> { //初始化一个ArrayList<Predicate>,存储多个谓词条件,这些条件最终会被组合成一个逻辑与(AND)表达式 List<Predicate> predicatesAndList = new ArrayList<>(); // deleted = 'true' if (null != productInstParams.getIsDeleted()) { predicatesAndList.add(criteriaBuilder.equal(root.get("deleted").as(Boolean.class), productInstParams.getIsDeleted())); } // name like %name% if (StringUtils.isNotBlank(productInstParams.getName())) { predicatesAndList.add(criteriaBuilder.like(root.get("name").as(String.class), productInstParams.getName())); } // runStatus = "运行中" if (StringUtils.isNotBlank(productInstParams.getRunStatus())) { predicatesAndList.add(criteriaBuilder.equal(root.get("runStatus").as(String.class), productInstParams.getRunStatus())); } // createdTime >= start if (!Objects.isNull(start)) { predicatesAndList.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createdTime").as(Date.class), start)); } // createdTime <= end if (!Objects.isNull(end)) { predicatesAndList.add(criteriaBuilder.lessThanOrEqualTo(root.get("createdTime").as(Date.class), end)); } // id in ('1','2') if (!CollectionUtils.isEmpty(productInstParams.getIds())) { CriteriaBuilder.In<String> in = criteriaBuilder.in(root.get("id").as(String.class)); productInstParams.getIds().forEach(in::value); predicatesAndList.add(in); } Predicate andPredicate = criteriaBuilder.and(predicatesAndList.toArray(new Predicate[predicatesAndList.size()])); query.where(andPredicate); return query.getRestriction(); }, pageable); return PageUtil.generatePageInfoVO(productInstPage); } }
解释:
jpa分页查询调的方法是:
Page findAll(@Nullable Specification spec, Pageable pageable);
该方法接受两个参数:
一个是 Specification 对象,用于构建复杂的查询条件;
另一个是之前创建的pageable对象,用于指定分页及排序信息。
点进去可以直接看到
下面我再解释一下这行代码
criteriaBuilder.equal(root.get("runStatus").as(String.class), productInstParams.getRunStatus());
1. criteriaBuilder 是javax.persistence.criteria.CriteriaBuilder的一个实例,它是用来构建JPQL查询条件的对象。
2. root 是代表查询主表的Root对象,它指向ProductInst实体类对应的数据库表。
3. root.get(“runStatus”) 表示获取ProductInst实体类中的runStatus属性(注意:这地方写的不是数据库的字段,我数据库的字段是:run_status)。这个方法返回的是一个Path<未知类型>对象,表示runStatus字段在查询路径上的位置。
4. .as(String.class) 是类型转换,确保runStatus被视为String类型,因为在数据库中它可能被映射为VARCHAR或者其他文本类型字段。
5. productInstParams.getRunStatus() 获取传入参数对象productInstParams中的runStatus属性值,这是一个待匹配的实际值。
综上所述:这段代码对应的sql
WHERE run_status = 'XXXX'
Repository:
@Repository public interface ProductInstRepository extends JpaRepository<ProductInst, String>, JpaSpecificationExecutor<ProductInst> { }
PageInfoVO:
package com.king.alice.common.base; import lombok.Getter; import lombok.Setter; import java.util.List; /** * @Author wlt * @Description 分页数据中的元素 * @Date 2022/8/26 **/ @Getter @Setter public class PageInfoVO<T> extends BaseVO{ private static final long serialVersionUID = -3542944936096780651L; /** * 总记录数 */ private long total; /** * 当前页 */ private int pageNum; /** * 每页的数量 */ private int pageSize; /** * 结果集 */ private List<T> list; }
PageUtil:
package com.king.alice.common.util; import com.king.alice.common.base.PageInfoVO; import org.springframework.data.domain.Page; /** * @author 大魔王 * @description: * @date 2024/3/22 11:02 */ public class PageUtil { /** * 根据Page对象生成PageInfoVO * * @param page Page包装对象 * @return PageDto 对象 */ @SuppressWarnings({"unchecked"}) public static <T> PageInfoVO<T> generatePageInfoVO(Page page) { PageInfoVO result = new PageInfoVO(); result.setPageNum(page.getNumber() + 1); result.setPageSize(page.getPageable().getPageSize()); result.setTotal(page.getTotalElements()); result.setList(page.getContent()); return result; } }
ProductInstParams:
package com.king.alice.manage.instance.params; import lombok.Data; import java.util.List; /** * @author 大魔王 * @description: TODO * @date 2024/3/21 16:56 */ @Data public class ProductInstParams { /** * 当前页 */ private int pageNo; /** * 每页的数量 */ private int pageSize; /** * 名字 */ private List<String> ids; /** * 名字 */ private String name; /** * 运行状态 */ private String runStatus; private String startDate; private String endDate; private Boolean isDeleted; }
测试:
响应结果:
控制台打印sql:
到此这篇关于SpringJPA 做分页条件查询的文章就介绍到这了,更多相关SpringJPA 分页内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!