JPA自定义查询List转Page分页失效,修改page/size参数无响应如何解决?
问题根因
你当前的实现属于典型的假分页,核心问题出在Repository层的自定义查询逻辑:
- 调用
entityManager.createQuery(query.where(predicate)).getResultList()时,没有给查询应用分页参数,会把所有符合筛选条件的Car记录全部从数据库查出来,无论传入的page和size是什么值 - 后续用全量列表封装
PageImpl时,总条数直接传了当前全量列表的长度,就算Page对象里携带分页参数,返回的内容还是全量数据,因此分页参数修改不会生效
修复方案
第一步:修改Repository层自定义搜索逻辑
需要调整三处逻辑:先构建统一查询条件、再查询符合条件的总记录数、最后给查询应用分页+排序参数后查询当前页数据,修改后代码如下:
@Override public Page<Car> search(Pageable pageable, String brand, String model, String type, Integer registrationYear, String color, String fuel, String transmission, String doors, double price) { int var = 0; CriteriaBuilder cb = entityManager.getCriteriaBuilder(); // 1. 构建公共查询条件 CriteriaQuery<Car> query = cb.createQuery(Car.class); Root<Car> car = query.from(Car.class); query.select(car); Predicate predicate = cb.greaterThan(car.get("id"), var); if (brand != null) predicate = cb.and(predicate, cb.equal(car.get("brand"), brand)); if (model != null) predicate = cb.and(predicate, cb.equal(car.get("model"), model)); if (type != null) predicate = cb.and(predicate, cb.equal(car.get("type"), type)); if (registrationYear != null) predicate = cb.and(predicate, cb.equal(car.get("registrationNumber"), registrationYear)); if (color != null) predicate = cb.and(predicate, cb.equal(car.get("color"), color)); if (fuel != null) predicate = cb.and(predicate, cb.equal(car.get("fuel"), Fuel.stringToFuelEnum(fuel))); if (transmission != null) predicate = cb.and(predicate, cb.equal(car.get("transmission"), Transmission.stringToTransmissionEnum(transmission))); if (doors != null) predicate = cb.and(predicate, cb.equal(car.get("doors"), doors)); if (price != 0) predicate = cb.and(predicate, cb.lessThan(car.get("price"), price)); query.where(predicate); // 2. 新增:查询符合条件的总记录数,用于Page对象计算总页数 CriteriaQuery<Long> countQuery = cb.createQuery(Long.class); Root<Car> countRoot = countQuery.from(Car.class); countQuery.select(cb.count(countRoot)).where(cb.and(predicate, cb.greaterThan(countRoot.get("id"), var))); Long total = entityManager.createQuery(countQuery).getSingleResult(); // 3. 新增:给查询应用分页+排序参数,查询当前页对应的数据 List<Car> carList = entityManager.createQuery(query) .setFirstResult((int) pageable.getOffset()) // 分页起始位置 .setMaxResults(pageable.getPageSize()) // 每页最多返回条数 .getResultList(); // 4. 传入真实总条数封装正确的Page对象 return new PageImpl<>(carList, pageable, total); }
第二步(可选优化):简化Controller层参数
Spring Boot默认配置下Pageable会自动解析请求中的page、size、sort参数,不需要手动重复声明page和size参数,简化后代码如下:
@GetMapping("/find") ResponseEntity<Page<CarDTO>> readAllCarsFiltered(@PageableDefault(page = 0, size = 5) Pageable pageable, @RequestParam(required = false) String brand, @RequestParam(required = false) String model, @RequestParam(required = false) String type, @RequestParam(required = false) Integer registrationYear, @RequestParam(required = false) String color, @RequestParam(required = false) String fuel, @RequestParam(required = false) String transmission, @RequestParam(required = false) String doors, @RequestParam(required = false, defaultValue = "9999999999") double price) { return ResponseEntity.ok(carService.customerSearch(pageable, brand, model, type, registrationYear, color, fuel, transmission, doors, price)); }
通过@PageableDefault注解可以直接配置默认分页参数,无需单独声明page和size的默认值。
内容的提问来源于stack exchange,提问作者Patryk Chojnacki
相关产品推荐
相关产品推荐

