Spring中按自定义前缀规则排序Device对象的实现方案
实现Device对象按指定前缀顺序排序的最优方案
给你几种实用的实现方式,根据你的场景选就行:
1. 内存中排序(Java Comparator实现)
如果已经把数据捞到内存里了,直接用自定义Comparator搞定。先定义前缀的优先级映射,然后按前缀权重排序,同前缀再按userId排序:
// 前缀优先级映射,按需求顺序给权重 private static final Map<String, Integer> PREFIX_PRIORITY = Map.of( "HCAD", 0, "GSAD", 1, "SLAD", 2, "GLAD", 3, "HCZD", 4 ); // 自定义排序器 Comparator<Device> deviceComparator = (d1, d2) -> { // 提取前4位作为前缀 String prefix1 = d1.getUserId().substring(0, 4); String prefix2 = d2.getUserId().substring(0, 4); // 先比前缀优先级 int prefixCompare = Integer.compare(PREFIX_PRIORITY.getOrDefault(prefix1, 5), PREFIX_PRIORITY.getOrDefault(prefix2, 5)); if (prefixCompare != 0) { return prefixCompare; } // 前缀相同就按userId字符串排序 return d1.getUserId().compareTo(d2.getUserId()); }; // 用Stream排序示例 List<Device> sortedDevices = deviceList.stream() .sorted(deviceComparator) .collect(Collectors.toList());
要是同前缀内想按数字后缀的数值排序(比如HCAD2排在HCAD10前面),就加个提取后缀的方法调整Comparator:
// 提取userId的数字后缀 private static Long getUserIdSuffix(String userId) { try { return Long.parseLong(userId.substring(4)); } catch (NumberFormatException e) { return 0L; // 非数字后缀的情况默认排前面,按需调整 } } // 调整后的排序器 Comparator<Device> deviceComparator = (d1, d2) -> { String prefix1 = d1.getUserId().substring(0, 4); String prefix2 = d2.getUserId().substring(0, 4); int prefixCompare = Integer.compare(PREFIX_PRIORITY.getOrDefault(prefix1, 5), PREFIX_PRIORITY.getOrDefault(prefix2, 5)); if (prefixCompare != 0) { return prefixCompare; } // 按数字后缀数值排序 return Long.compare(getUserIdSuffix(d1.getUserId()), getUserIdSuffix(d2.getUserId())); };
2. 数据库层面排序(Spring Data JPA实现)
数据量大的话,直接在数据库排序更高效,毕竟数据库的排序引擎更专业。用Spring Data JPA可以这么搞:
方式1:自定义查询方法
直接写带排序逻辑的SQL查询:
@Repository public interface DeviceRepository extends JpaRepository<Device, Long> { @Query("SELECT d FROM Device d ORDER BY " + "CASE SUBSTRING(d.userId, 1, 4) " + " WHEN 'HCAD' THEN 0 " + " WHEN 'GSAD' THEN 1 " + " WHEN 'SLAD' THEN 2 " + " WHEN 'GLAD' THEN 3 " + " WHEN 'HCZD' THEN 4 " + " ELSE 5 END, " + "d.userId") List<Device> findAllOrderedByPrefix(); }
方式2:动态构建查询(带其他条件时用)
如果还要加其他查询条件,用Specification动态拼排序:
@Repository public interface DeviceRepository extends JpaRepository<Device, Long>, JpaSpecificationExecutor<Device> { } // 业务层调用示例 public List<Device> getSortedDevices() { Specification<Device> spec = (root, query, cb) -> { // 构建前缀排序规则 Expression<Integer> prefixOrder = cb.selectCase() .when(cb.equal(cb.substring(root.get("userId"), 1, 4), "HCAD"), 0) .when(cb.equal(cb.substring(root.get("userId"), 1, 4), "GSAD"), 1) .when(cb.equal(cb.substring(root.get("userId"), 1, 4), "SLAD"), 2) .when(cb.equal(cb.substring(root.get("userId"), 1, 4), "GLAD"), 3) .when(cb.equal(cb.substring(root.get("userId"), 1, 4), "HCZD"), 4) .otherwise(5); // 设置排序:先按前缀权重,再按userId query.orderBy(cb.asc(prefixOrder), cb.asc(root.get("userId"))); return cb.conjunction(); // 这里可以加其他查询条件,比如cb.equal(root.get("status"), 1) }; return deviceRepository.findAll(spec); }
3. 全局默认排序(实现Comparable接口)
如果这个排序规则是Device对象的默认排序逻辑,直接让Device类实现Comparable接口:
public class Device implements Comparable<Device> { private String userId; private LocalDateTime activationDatetime; // 其他属性、getter、setter private static final Map<String, Integer> PREFIX_PRIORITY = Map.of( "HCAD", 0, "GSAD", 1, "SLAD", 2, "GLAD", 3, "HCZD", 4 ); @Override public int compareTo(Device other) { String prefix1 = this.userId.substring(0, 4); String prefix2 = other.userId.substring(0, 4); int prefixCompare = Integer.compare(PREFIX_PRIORITY.getOrDefault(prefix1, 5), PREFIX_PRIORITY.getOrDefault(prefix2, 5)); if (prefixCompare != 0) { return prefixCompare; } return this.userId.compareTo(other.userId); } }
之后直接用Collections.sort(deviceList)就能按规则排序,适合全局默认排序的场景。
内容的提问来源于stack exchange,提问作者Aashish Prajapati
相关产品推荐
相关产品推荐

