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

Spring Boot+JPA/Hibernate多列自定义排序分页查询方案咨询

自定义排序分页搜索API实现方案

实体类定义

首先对应数据库表创建JPA实体:

import jakarta.persistence.*;

@Entity
@Table(name = "TABLE_1")
public class EntityRecord {
    @Column(name = "ENTITY_TYPE")
    private String entityType;

    @Column(name = "ENTITY_NAME")
    private String entityName;

    @Column(name = "PERSON_EID")
    private Long personEid;

    @Column(name = "PERSON_ROLE")
    private String personRole;

    // 生成无参/全参构造函数,以及所有字段的getter/setter
}

核心实现:自定义排序的分页查询

针对ENTITY_TYPE的自定义顺序需求,推荐以下三种实现方式,优先选择数据库层面排序的方案(性能更优):

方式1:JPQL CASE表达式实现排序

通过JPQL的CASE语句为每个ENTITY_TYPE分配排序权重,直接在数据库层面完成排序,结合Spring JPA的分页能力:

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

public interface EntityRecordRepository extends JpaRepository<EntityRecord, Long> {

    @Query(value = "SELECT er FROM EntityRecord er " +
            "ORDER BY " +
            "CASE er.entityType " +
            "   WHEN 'Owner' THEN 1 " +
            "   WHEN 'Exec' THEN 2 " +
            "   WHEN 'President' THEN 3 " +
            "END ASC, " +
            "er.entityName ASC")
    Page<EntityRecord> findAllWithCustomSort(Pageable pageable);
}

调用时,Pageable仅需传入分页参数(页码、每页数量),排序逻辑已固化在JPQL中。

方式2:Hibernate @Formula映射排序权重字段

在实体类中通过@Formula注解生成一个虚拟的排序权重字段,之后即可直接使用Spring JPA的标准排序机制:
修改实体类,添加权重字段:

import jakarta.persistence.*;

@Entity
@Table(name = "TABLE_1")
public class EntityRecord {
    @Column(name = "ENTITY_TYPE")
    private String entityType;

    // 生成排序权重的虚拟字段
    @Formula("CASE ENTITY_TYPE WHEN 'Owner' THEN 1 WHEN 'Exec' THEN 2 WHEN 'President' THEN 3 ELSE 4 END")
    private Integer entityTypeOrder;

    @Column(name = "ENTITY_NAME")
    private String entityName;

    @Column(name = "PERSON_EID")
    private Long personEid;

    @Column(name = "PERSON_ROLE")
    private String personRole;

    // 构造函数、getter/setter(需包含entityTypeOrder的getter)
}

Repository层无需自定义查询,直接使用默认方法:

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface EntityRecordRepository extends JpaRepository<EntityRecord, Long> {
}

调用时构造带排序规则的Pageable:

Sort sort = Sort.by(Sort.Order.asc("entityTypeOrder"), Sort.Order.asc("entityName"));
Pageable pageable = PageRequest.of(pageNum, pageSize, sort);
Page<EntityRecord> result = repository.findAll(pageable);

方式3:内存排序(仅适合小数据量)

如果数据量极小,可先分页查询数据,再在内存中完成自定义排序。此方式性能较差,不推荐大数据场景:

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.List;
import java.util.Map;

@Service
public class EntityRecordService {

    private final EntityRecordRepository repository;
    // 定义自定义排序权重映射
    private static final Map<String, Integer> ENTITY_TYPE_SORT_WEIGHT = Map.of(
            "Owner", 1,
            "Exec", 2,
            "President", 3
    );

    public EntityRecordService(EntityRecordRepository repository) {
        this.repository = repository;
    }

    public Page<EntityRecord> search(Pageable pageable) {
        Page<EntityRecord> pageData = repository.findAll(pageable);
        List<EntityRecord> sortedList = pageData.getContent().stream()
                .sorted(Comparator.comparingInt(record -> ENTITY_TYPE_SORT_WEIGHT.getOrDefault(record.getEntityType(), 4))
                        .thenComparing(EntityRecord::getEntityName))
                .toList();
        return new PageImpl<>(sortedList, pageable, pageData.getTotalElements());
    }
}

搜索API实现

在Controller层暴露分页搜索接口:

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 EntityRecordController {

    private final EntityRecordRepository repository;

    public EntityRecordController(EntityRecordRepository repository) {
        this.repository = repository;
    }

    @GetMapping("/api/entities")
    public Page<EntityRecord> getEntities(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size) {
        // 对应方式1的调用
        // return repository.findAllWithCustomSort(PageRequest.of(page, size));

        // 对应方式2的调用
        Sort sort = Sort.by(Sort.Order.asc("entityTypeOrder"), Sort.Order.asc("entityName"));
        return repository.findAll(PageRequest.of(page, size, sort));
    }
}

注意事项

  • 若ENTITY_TYPE的可选值需动态调整,可将排序权重配置在application.yml中,通过@Value注入映射,避免硬编码。
  • 方式1和方式2均为数据库层面排序,性能更优,推荐生产环境使用;方式3仅适合测试或数据量极小的场景。
  • 若使用MySQL,可替换CASE表达式为FIELD函数(如ORDER BY FIELD(ENTITY_TYPE, 'Owner', 'Exec', 'President'), ENTITY_NAME ASC),但此方式依赖数据库方言,跨数据库兼容性差。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 13:35:15