前言:
相信小伙伴们的项目很多都用到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:
完美实现!