在项目写的差不多的时候,突然增加需求,要对之前的接口返回的list进行排序,要一个个回去重新添加排序好麻烦,所以尝试写了拦截器,拦截接口统一排序:
公共响应体
先是Controller返回的公共响应体:
import java.io.Serializable;
public class CommonResult<T> implements Serializable {
private String message;
private int code;
private T data;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public CommonResult() {
}
public CommonResult(int code, String message, T data) {
this.message = message;
this.code = code;
this.data = data;
}
public static <T> CommonResult<T> success(String message, T data) {
return new CommonResult<>(200, message, data);
}
}
配置类:
这个配置类的目的是:
有时排序字段可能不一致,所以通过这中配置的方式来灵活配置想要的排序字段
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
@ConfigurationProperties(prefix = "sort")
@EnableConfigurationProperties
public class SortConfig {
private Map<String, String> sortMap = new HashMap<>();
public Map<String, String> getSortMap() {
return sortMap;
}
public void setSortMap(Map<String, String> sortMap) {
this.sortMap = sortMap;
}
}
配置nacos中定义的map可以实现灵活排序
拦截器:ResultAspect
通过反射来遍历object的每个属性,若是集合则排序,并且会递归对象属性中的嵌套集合;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
@Aspect
@Component
public class ResultAspect {
private SortConfig sortConfig;
/**
* 将所有controller层级的方法作为切入点
*/
@Pointcut(" execution(public *controller的层级路径")
public void handlePlaceholder() {
}
/**
* pointcut/value:这两个属性的作用是一样的, 它们都属于指定切入点对应的切入表达式*。
* 一样既可以是已有的切入点,也可直接定义切入点表达式。当指定J pointcut属性值后,value属性值将会被覆盖。
* 在这里把已经定义好的 handLePlaceholder 作为切入点
* returning:该属性指定一个形参名, 用于表示Advice方法中可定义与此同名的形参,该形参可用F访问目标方法的返回值。
* 除此之外,在Advice方法中定 义该形参(代表目标方法的返回值)时指定的类型,会限制目标方法必须返回指定类型的值或没有返回值。
*/
@AfterReturning(returning = "ret", pointcut = "handlePlaceholder()")
public void doAfterReturning(Object ret) throws Throwable {
// 在清求処理之后迸行搓截処理
if (ret != null) {
CommonResult<?> result = (CommonResult<?>) ret;
Object data = result.getData();
if (data instanceof List<?>) {
// 排最外层
List<Object> dataList = (List<Object>) data;
dataList.sort(new CustomFieldComparator(sortConfig.getSortMap()));
//排内居嵌套
sortObjField(dataList);
}
}
}
/**
* 递归,排序属性中的list
*
* @param dataList 数据的List
* @throws IllegalAccessException 漂移车
*/
public void sortObjField(List<?> dataList) throws IllegalAccessException {
// 遍历data中的属性中是否有list
for (Object obj : dataList) {
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
Class<?> type = field.getType();
// 是否是list
if (type.isAssignableFrom(List.class)) {
List<Object> list = (List<Object>) field.get(obj);
list.sort(new CustomFieldComparator(sortConfig.getSortMap()));
// 递归
sortObjField(list);
}
}
}
}
static class CustomFieldComparator implements Comparator<Object> {
private Map<String, String> sortMap;
CustomFieldComparator(Map<String, String> sortMap) {
this.sortMap = sortMap;
}
// 设置一个默认的排序字段
private static final String SHORT_NAME = " shortName";
@SneakyThrows
@Override
public int compare(Object o1, Object o2) {
String sortName = this.getSortName(o1);
//根据指定字段进行比较,并返回比较结果
//假设指定字段为fieldName, 类型为String
String v1 = this.getFieldValueByFieldName(sortName, o1);
if (v1 == null) {
return 0;
}
String v2 = this.getFieldValueByFieldName(sortName, o2);
return v1.compareTo(v2);
}
public String getSortName(Object obj) {
String[] split = obj.getClass().getName().split(".");
String className = split[split.length - 1];
// 根据类名,获取在nacos中配置的排序字段,若获取不到值,则使用默认的排序字段
String sortName = sortMap.get(className);
sortName = sortName == null ? SHORT_NAME : sortName;
return sortName;
}
/**
*
* @param fieldName 属性名
* @param object 对象
* @return 返回属性值
*/
private String getFieldValueByFieldName(String fieldName, Object object) {
try {
Field field = object.getClass().getDeclaredField(fieldName);
// 设置对象的访问权限,保证对private的属性的访问
field.setAccessible(true);
return ((String) field.get(object)).toLowerCase();
} catch (Exception e) {
return null;
}
}
}
}