目录
排序场景
在面向前端数据展示的应用场景中,我们旨在实现一个更加灵活的排序机制,该机制能够支持对从后端传递至前端的全部字段进行排序操作。用户通过点击排序按钮,即可实现对特定字段或多字段的升序或降序排列,从而快速实现页面的排序展示效果。
排序实现思路
1. 静态代码排序实现
- 内容:后端对前端传递的所有字段进行判断,以编写代码的方式实现排序逻辑
- 优点:采用静态代码实现排序逻辑的方法简洁明了,能够适应各种不同的场景
- 缺点:该方法会导致代码冗余,每个报表都需要独立实现排序逻辑,缺乏代码的可复用性
2.数据库驱动排序实现
- 内容:基于数据库排序的方式,前端将要排序的字段传给后端,后端转成数据库字段进行排序
- 优点:当涉及简单字段排序时,利用数据库自身的排序功能可以提高排序效率
- 缺点:该方法不适用于复合字段(即需要计算得出的字段)或前端字段与数据库字段没有直接映射关系的情况
3. 基于Java反射的动态排序实现
- 内容:前端传递排序字段和排序方式,排序字段基于后端提供的返回字段。在接口层接收到查询请求后,首先通过业务逻辑层获取到一个尚未排序的数据集合。随后,通过调用一个通用的排序工具来对集合进行排序处理,最终返回经过排序的集合。
- 优点:采用通用排序工具使得排序逻辑与业务逻辑和应用逻辑分离,利用Java反射机制实现了这一过程,从而显著提升了系统的可扩展性和灵活性。
- 缺点:Java反射机制的使用会增加资源消耗;同时,它可能会违背封装原则,并有可能引入安全风险。
通用排序工具 SortListUtil
sortListUtil是一个java语言实现的工具类方法。通过泛型、Comparator和Java 反射机制实现单字段排序,多字段排序。其中sortListByField方法处理集合单字段排序;sortListByFields方法处理集合多字段排序;getComparator方法为通用的排序方法,封装了处理集合排序字段的逻辑,通过这个方法组装成comparator对象,最后统一使用stream().sorted()方法进行排序。
- 方法内容
package com.streamax.bus.report.server.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
@Component
@Slf4j
public class SortListUtil<T> {
public List<T> sortListByField(
List<T> list, String fieldName, Integer orderBySort) {
if (fieldName == null || fieldName == "") {
return list;
}
// 构建getter方法名
String getterName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
Comparator<T> comparator = getComparator(getterName, orderBySort);
// 使用sorted和collect来排序并收集结果
return list.stream()
.sorted(comparator)
.collect(Collectors.toList());
}
/**
* 多字段排序
*
* @param list
* @param fieldNames
* @param orderBySort
* @return
*/
public List<T> sortListByFields(
List<T> list, String[] fieldNames, Integer orderBySort) {
if (fieldNames == null || fieldNames.length == 0) {
return list;
}
Comparator<T> comparator = null;
for (String fieldName : fieldNames) {
// 构建getter方法名
String getterName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
if (comparator == null) {
comparator = getComparator(getterName, orderBySort);
} else {
comparator.thenComparing(getComparator(getterName, orderBySort));
}
}
// 使用sorted和collect来排序并收集结果
return list.stream()
.sorted(comparator)
.collect(Collectors.toList());
}
private Comparator<T> getComparator(String getterName, Integer orderBySort) {
Comparator<T> comparator = (dto1, dto2) -> {
try {
Class<?> clazz = dto1.getClass();
// 获取对应的getter方法
Method getterMethod = clazz.getMethod(getterName);
// 调用getter方法获取值
Object value1 = getterMethod.invoke(dto1);
Object value2 = getterMethod.invoke(dto2);
// 关于有值为空的处理
if (value1 == null || value2 == null) {
return (value1 == null) ? (value1 == null ? -1 : 0) : 1;
}
// 比较两个值
if (value1 instanceof Comparable && value2 instanceof Comparable) {
if (orderBySort != null && orderBySort == 1) {
return ((Comparable) value2).compareTo(value1);
}
return ((Comparable) value1).compareTo(value2);
} else {
throw new IllegalArgumentException("Field values are not comparable");
}
} catch (Exception e) {
throw new RuntimeException("Error comparing field values", e);
}
};
return comparator;
}
}
- 使用方式
-
public static void main(String[] args) { QueryParams reqQuery = new QueryParams(); reqQuery.setOrderByCommon("排序字段"); reqQuery.setOrderBySort("排序类型 升序,降序"); ObjectList resultList = new ArrayList<>(); resultList = new SortListUtil<ObjectList>().sortListByField(resultList, reqQuery.getOrderByCommon(), reqQuery.getOrderBySort()); }
- resultList : 需要排序的集合
- reqQuery:前端请求参数
- orderByCommon:需要排序的字段
- orderBySort:排序的方式(正序,倒序)
结语
本文简单阐述了排序功能的实现策略,并提供了一款基于Java反射机制的排序工具类名为SortListUtil。该工具于2024年11月5日上午完成编码,并已通过初步的单元测试和系统测试。需要注意的是,目前提供的版本并非工具类的最终形态。我们欢迎各位同仁提出宝贵的优化建议,共同探讨和提升工具的性能与可用性。