导读:本期聚焦于小伙伴创作的《如何使用JPA Criteria API实现复杂筛选与后端分页功能》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何使用JPA Criteria API实现复杂筛选与后端分页功能》有用,将其分享出去将是对创作者最好的鼓励。

在Java持久层开发中,当业务需要支持多维度动态筛选,同时要求返回分页结果时,JPA Criteria API是比JPQL更灵活的查询构建方案,它可以在运行时动态拼接查询条件,还能和分页参数无缝结合。

如何使用JPA Criteria API实现复杂筛选与后端分页功能

JPA Criteria API基础概念

JPA Criteria API是JPA 2.0引入的类型安全查询API,它通过面向对象的方式构建查询,避免了拼接字符串带来的SQL注入风险,也解决了JPQL无法动态适配条件变化的问题。核心组件包括CriteriaBuilderCriteriaQueryRoot等。

核心组件说明

  • CriteriaBuilder:用于创建查询的各个部分,比如条件表达式、排序规则等
  • CriteriaQuery:代表整个查询对象,用于设置查询的返回类型、筛选条件、排序等
  • Root:代表查询的根实体,通过它可以获取实体的各个属性,用于构建条件

复杂筛选条件构建

复杂筛选通常指条件不是固定的,会根据前端传入的参数动态增减,比如用户列表查询可能同时支持按用户名、状态、创建时间范围筛选,部分参数可能为空不需要加入查询。

动态条件拼接示例

假设我们有一个User实体,包含idusernamestatuscreateTime属性,现在需要构建动态筛选条件:

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;

public class UserQueryCondition {
    private String username;
    private Integer status;
    private Long startTime;
    private Long endTime;

    // getter和setter省略

    /**
     * 构建动态筛选条件
     */
    public Predicate buildPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
        List<Predicate> predicates = new ArrayList<>();
        // 用户名模糊筛选,非空时加入条件
        if (username != null && !username.trim().isEmpty()) {
            predicates.add(criteriaBuilder.like(root.get("username"), "%" + username + "%"));
        }
        // 状态精确筛选,非空时加入条件
        if (status != null) {
            predicates.add(criteriaBuilder.equal(root.get("status"), status));
        }
        // 创建时间范围筛选
        if (startTime != null) {
            predicates.add(criteriaBuilder.ge(root.get("createTime"), startTime));
        }
        if (endTime != null) {
            predicates.add(criteriaBuilder.le(root.get("createTime"), endTime));
        }
        // 将所有条件用and连接
        return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
    }
}

结合后端分页实现完整查询

后端分页需要返回指定页的数据以及总条数,Spring Data JPA提供了PageablePage接口来支持分页,我们可以将Criteria API构建的查询和分页参数结合。

Repository层实现

自定义Repository接口,继承JpaSpecificationExecutor来获得支持Specification的查询能力:

import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.PagingAndSortingRepository;

public interface UserRepository extends PagingAndSortingRepository<User, Long>, JpaSpecificationExecutor<User> {
}

Service层实现完整分页查询

在Service中组合筛选条件和分页参数,调用Repository的方法获取分页结果:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    /**
     * 带复杂筛选的后端分页查询
     */
    public Page<User> queryUserByCondition(UserQueryCondition condition, Pageable pageable) {
        // 构建Specification,将动态条件适配到Spring Data JPA的查询中
        Specification<User> specification = (root, query, criteriaBuilder) -> {
            // 调用条件构建方法生成筛选条件
            return condition.buildPredicate(root, query, criteriaBuilder);
        };
        // 执行分页查询,返回Page对象包含数据和分页信息
        return userRepository.findAll(specification, pageable);
    }
}

Controller层接收参数调用

Controller层接收前端传入的筛选参数和分页参数,调用Service返回结果:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/users")
    public Page<User> listUsers(
            @RequestParam(required = false) String username,
            @RequestParam(required = false) Integer status,
            @RequestParam(required = false) Long startTime,
            @RequestParam(required = false) Long endTime,
            @RequestParam(defaultValue = "0") Integer page,
            @RequestParam(defaultValue = "10") Integer size) {

        // 构建查询条件对象
        UserQueryCondition condition = new UserQueryCondition();
        condition.setUsername(username);
        condition.setStatus(status);
        condition.setStartTime(startTime);
        condition.setEndTime(endTime);

        // 构建分页参数,默认按创建时间倒序
        Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createTime"));

        return userService.queryUserByCondition(condition, pageable);
    }
}

注意事项

  • 构建模糊查询时,需要对传入的参数做非空校验,避免拼接出like '%%'这种无意义的条件,影响查询性能
  • 如果筛选条件包含关联实体的属性,需要通过root.join()方法关联对应的实体后再获取属性
  • 分页参数中page默认从0开始,和前端常见的从1开始的页码需要做转换适配
  • 如果查询需要返回自定义DTO而不是实体,可以通过CriteriaQuery.multiselect()方法指定返回的字段,构造自定义结果

JPA_Criteria_API复杂筛选后端分页Spring_Data_JPA修改时间:2026-07-07 00:30:42

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。