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

JPA Specification中通过FIND_IN_SET实现CriteriaQuery IN查询自定义排序

JPA Specification适配FIND_IN_SET实现IN查询结果按传入ID顺序排序方案

改动步骤

  • 第一步:扩展操作枚举,新增两类操作值
    在你定义的Operation枚举中新增IN查询和自定义排序枚举:
public enum Operation {
    // 原有枚举保持不变
    EQUAL, MATCH, SORT_ASC, SORT_DESC,
    // 新增枚举
    IN, // 标准IN查询操作
    SORT_BY_IN_LIST // 按传入列表顺序排序操作
}
  • 第二步:调整SearchCriteria参数逻辑,支持传入List类型的参数值,适配IN查询和ID列表入参。
  • 第三步:修改toPredicate方法,新增对应分支逻辑,完整修改后代码如下:
@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
    List<Predicate> predicates = new ArrayList<>();
    for (SearchCriteria criteria : list) {
        switch (criteria.getOperation()) {
            // 原有逻辑保持不变
            case EQUAL:
                predicates.add((Objects.isNull(criteria.getJoinMap()) || criteria.getJoinMap().isEmpty())
                        ? builder.equal(root.get(criteria.getKey()), criteria.getValue())
                        : builder.equal(getOrCreateJoins(root, criteria.getJoinMap()).get(criteria.getKey()),
                                criteria.getValue()));
                break;
            case MATCH:
                predicates.add((Objects.isNull(criteria.getJoinMap()) || criteria.getJoinMap().isEmpty())
                        ? builder.like(builder.lower(root.get(criteria.getKey())),
                                "%" + criteria.getValue().toString().toLowerCase() + "%")
                        : builder.like(
                                builder.lower(getOrCreateJoins(root, criteria.getJoinMap()).get(criteria.getKey())),
                                "%" + criteria.getValue().toString().toLowerCase() + "%"));
                break;
            case SORT_ASC:
                query.orderBy((Objects.isNull(criteria.getJoinMap()) || criteria.getJoinMap().isEmpty())
                        ? builder.asc(root.get(criteria.getKey()))
                        : builder.asc(getOrCreateJoins(root, criteria.getJoinMap()).get(criteria.getKey())));
                break;
            case SORT_DESC:
                query.orderBy((Objects.isNull(criteria.getJoinMap()) || criteria.getJoinMap().isEmpty())
                        ? builder.desc(root.get(criteria.getKey()))
                        : builder.desc(getOrCreateJoins(root, criteria.getJoinMap()).get(criteria.getKey())));
            // 新增IN查询分支
            case IN:
                Path<Object> inPath = (Objects.isNull(criteria.getJoinMap()) || criteria.getJoinMap().isEmpty())
                        ? root.get(criteria.getKey())
                        : getOrCreateJoins(root, criteria.getJoinMap()).get(criteria.getKey());
                predicates.add(inPath.in((List<?>) criteria.getValue()));
                break;
            // 新增按传入列表顺序排序分支
            case SORT_BY_IN_LIST:
                Path<Object> sortPath = (Objects.isNull(criteria.getJoinMap()) || criteria.getJoinMap().isEmpty())
                        ? root.get(criteria.getKey())
                        : getOrCreateJoins(root, criteria.getJoinMap()).get(criteria.getKey());
                // 把传入的列表转为逗号分隔字符串,兼容数字、字符串类型的ID
                String idListStr = ((List<?>) criteria.getValue()).stream()
                        .map(String::valueOf)
                        .collect(Collectors.joining(","));
                // 调用MySQL原生FIND_IN_SET函数
                Expression<Integer> findInSetExpr = builder.function(
                        "FIND_IN_SET",
                        Integer.class,
                        sortPath.as(String.class),
                        builder.literal(idListStr)
                );
                // 按函数返回的序号升序排序,匹配传入列表顺序
                query.orderBy(builder.asc(findInSetExpr));
                break;
            default:
                break;
        }
    }
    return isSearchOperationOr ? builder.or(predicates.toArray(new Predicate[0]))
            : builder.and(predicates.toArray(new Predicate[0]));
}

使用说明

当你需要实现IN查询返回结果与传入ID顺序一致时,构造两个SearchCriteria对象即可:

  1. 第一个参数:operation为IN,key为ID字段名,value为待查询的ID列表
  2. 第二个参数:operation为SORT_BY_IN_LIST,key为ID字段名,value为和IN查询完全相同的ID列表

注意:本方案依赖MySQL方言,切换数据库时需要替换为对应数据库的自定义排序函数实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 06:42:00