You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于多可选参数的Spring Data JPA分页搜索功能实现求助

基于可选参数的分页搜索实现方案

先纠正实体类的关键问题

你的UserDetails实体类将age设为主键不合理,会导致同年龄用户主键冲突,建议修改为独立自增主键:

@Entity
@Table(name = "userDetails")
public class UserDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id; // 新增独立主键字段
    private int age;
    private String manglik;
    private String maritalStatus;
    private String manglikStatus;
    private String religion;
    private String caste;
    private String location;
    
    // 省略getter、setter、构造方法
}

实现步骤

1. 创建搜索参数DTO

定义一个DTO接收前端的可选搜索参数和分页参数:

public class UserSearchCriteria {
    private Integer age;
    private String manglik;
    private String maritalStatus;
    private String manglikStatus;
    private String religion;
    private String caste;
    private String location;
    
    // 分页默认参数
    private int page = 0;
    private int size = 10;
    private String sortBy = "id";
    private String sortDir = "asc";
    
    // 省略getter、setter
}

2. 编写动态查询Specification

利用Specification接口动态拼接非空参数的查询条件:

import org.springframework.data.jpa.domain.Specification;
import jakarta.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;

public class UserDetailsSpecification {
    public static Specification<UserDetails> getSpecification(UserSearchCriteria criteria) {
        return (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            if (criteria.getAge() != null) {
                predicates.add(criteriaBuilder.equal(root.get("age"), criteria.getAge()));
            }
            if (criteria.getManglik() != null && !criteria.getManglik().isEmpty()) {
                predicates.add(criteriaBuilder.equal(root.get("manglik"), criteria.getManglik()));
            }
            if (criteria.getMaritalStatus() != null && !criteria.getMaritalStatus().isEmpty()) {
                predicates.add(criteriaBuilder.equal(root.get("maritalStatus"), criteria.getMaritalStatus()));
            }
            if (criteria.getManglikStatus() != null && !criteria.getManglikStatus().isEmpty()) {
                predicates.add(criteriaBuilder.equal(root.get("manglikStatus"), criteria.getManglikStatus()));
            }
            if (criteria.getReligion() != null && !criteria.getReligion().isEmpty()) {
                predicates.add(criteriaBuilder.equal(root.get("religion"), criteria.getReligion()));
            }
            if (criteria.getCaste() != null && !criteria.getCaste().isEmpty()) {
                predicates.add(criteriaBuilder.equal(root.get("caste"), criteria.getCaste()));
            }
            if (criteria.getLocation() != null && !criteria.getLocation().isEmpty()) {
                predicates.add(criteriaBuilder.equal(root.get("location"), criteria.getLocation()));
            }
            
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        };
    }
}

3. Service层实现分页查询逻辑

注入Repository,封装分页和查询条件的调用:

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.stereotype.Service;

@Service
public class UserDetailsService {
    private final UserDetailsRepository userDetailsRepository;

    public UserDetailsService(UserDetailsRepository userDetailsRepository) {
        this.userDetailsRepository = userDetailsRepository;
    }

    public Page<UserDetails> searchUsers(UserSearchCriteria criteria) {
        Sort sort = Sort.by(Sort.Direction.fromString(criteria.getSortDir()), criteria.getSortBy());
        Pageable pageable = PageRequest.of(criteria.getPage(), criteria.getSize(), sort);
        Specification<UserDetails> spec = UserDetailsSpecification.getSpecification(criteria);
        return userDetailsRepository.findAll(spec, pageable);
    }
}

4. Controller层接收请求并返回结果

通过@ModelAttribute接收参数,返回分页结果:

import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/users")
public class UserDetailsController {
    private final UserDetailsService userDetailsService;

    public UserDetailsController(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @GetMapping("/search")
    public ResponseEntity<Page<UserDetails>> searchUsers(@ModelAttribute UserSearchCriteria criteria) {
        Page<UserDetails> result = userDetailsService.searchUsers(criteria);
        return ResponseEntity.ok(result);
    }
}

使用说明

前端可通过GET请求传递任意可选参数,例如:
/users/search?age=28&religion=Hindu&page=1&size=15
未传递的参数不会加入查询条件,返回的Page对象包含总条数、总页数、当前页数据等完整分页信息。

内容的提问来源于stack exchange,提问作者Ravi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 18:45:33