通用实例列表排序实现

1. ModelsSortHelper 

import com.google.common.base.Strings;

import org.springframework.beans.BeanUtils;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import lombok.Data;

/**
 * Model列表排序帮助类
 */
public class ModelsSortHelper {

    /**
     * Model列表排序
     *
     * @param sortStr 排序条件.(必须以 字段名1__asc|desc[,字段名2__asc|desc...] 这样的格式.如 "name_asc,age_desc")
     *                对应的字段必须实现 Comparable 接口
     * @param source  列表
     * @param tClass  Model类型
     * @param <T>     Model类型
     * @return 排序后的列表
     */
    public static <T> List<T> sort(String sortStr, List<T> source, Class<T> tClass) {
        // 转换排序条件列表
        List<SortItem> keys = toKeys(sortStr);
        // 如果没有排序条件,直接返回原列表
        if (CollectionUtils.isEmpty(keys)) {
            return source;
        }
        if (CollectionUtils.isEmpty(keys)) {
            return source;
        }
        //根据排序条件列表构建 比较器Comparator<T>
        Comparator<T> comparator = buildComparator(keys, tClass);
        // 如果构建失败(字段不存在,字段类型没有实现Comparable等),直接返回原列表
        if (comparator == null) {
            return source;
        }

        // 实现排序
        return source.stream()
                .sorted(comparator)
                .collect(Collectors.toList());
    }

    /**
     * 转换为排序算法列表
     *
     * @param sortType 排序算法
     */
    private static List<SortItem> toKeys(String sortType) {
        if (Strings.isNullOrEmpty(sortType)) {
            return Collections.emptyList();
        }

        String[] sortItems = sortType.split(",");
        return Arrays.stream(sortItems)
                .map(SortItem::new)
                .collect(Collectors.toList());
    }

    /**
     * 构建比较器链
     *
     * @param sorts  排序列表
     * @param tClass Model类型
     * @param <T>    Model类型
     * @return 比较器
     */
    private static <T> Comparator<T> buildComparator(List<SortItem> sorts, Class<T> tClass) {
        // 多个Sort条件,则实现 Comparator的thenComparing
        Comparator<T> comparator = null;
        for (SortItem sort : sorts) {
            Comparator<T> theComparator = buildComparator(sort, tClass);
            if (theComparator == null) {
                throw new RuntimeException("创建比较器异常.对应的排序字段为:" + sort.getField());
            }
            // 第一个排序条件为主排序
            if (comparator == null) {
                comparator = theComparator;
            } else {
                // 第2个及以后的为辅助排序
                comparator = comparator.thenComparing(theComparator);
            }
        }

        return comparator;
    }

    /**
     * 构建单个比较器
     *
     * @param sortItem  排序列表
     * @param tClass Model类型
     * @param <T>    Model类型
     * @return 比较器
     */
    private static <T> Comparator<T> buildComparator(SortItem sortItem, Class<T> tClass) {
        String field = sortItem.getField();

        return (T o1, T o2) -> sortItem.isAsc()
                ? getVal(o1, tClass, field).compareTo(getVal(o2, tClass, field))
                : getVal(o2, tClass, field).compareTo(getVal(o1, tClass, field));
    }

    /**
     * 获取字段对应的值的方法
     * @param instance 比较实例
     * @param tClass Model类型
     * @param field 比较字段
     * @param <T> Model类型
     * @return 返回一个Comparable 类型的值
     */
    private static <T> Comparable getVal(T instance, Class<T> tClass, String field) {
        // BeanUtils 已缓存到一个Map里
        PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(tClass, field);
        Method readMethod = propertyDescriptor.getReadMethod();
        try {
            Object val = readMethod.invoke(instance);
            if (val instanceof Comparable) {
                return (Comparable) val;
            }
        } catch (Exception ex) {
            throw new RuntimeException("配置排序字段异常-1");
        }

        throw new RuntimeException("配置排序字段异常-3");
    }

    @Data
    static class SortItem {
        private String field;
        private String type;

        public SortItem(String sort) {
            String[] arr = sort.split("__");
            Assert.isTrue(arr.length == 2);
            Assert.isTrue(!Strings.isNullOrEmpty(arr[0]) && !Strings.isNullOrEmpty(arr[1]));
            Assert.isTrue("asc".equalsIgnoreCase(arr[1]) || "desc".equalsIgnoreCase(arr[1]));
            field = arr[0];
            type = arr[1];
        }

        public boolean isAsc() {
            return "asc".equalsIgnoreCase(type);
        }
    }
}

2.测试

import java.math.BigDecimal;
import java.time.LocalDateTime;

import lombok.Builder;
import lombok.Data;

/**
 * Created by zhangjy on 2020/8/10.
 */
@Data
@Builder
public class StudentModel {
    private int id;
    private String name;
    private BigDecimal score;// name;
    private LocalDateTime birthday;
}

 

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by zhangjy on 2020/8/10.
 */
public class ModelSortTest {
    static final List<StudentModel> STUDENT_MODELS = new ArrayList<>();

    static {
        StudentModel studentModel1 = StudentModel.builder()
                .id(100)
                .name("张三")
                .score(BigDecimal.TEN)
                .birthday(LocalDateTime.of(2001,1,1,0,0))
                .build();
        StudentModel studentModel2 = StudentModel.builder()
                .id(101)
                .name("李四")
                .birthday(LocalDateTime.of(1999,1,1,0,0))
                .score(BigDecimal.ZERO)
                .build();
        StudentModel studentModel3 = StudentModel.builder()
                .id(102)
                .name("王五")
                .score(BigDecimal.ONE)
                .birthday(LocalDateTime.of(2003,1,1,0,0))
                .build();
        StudentModel studentModel4 = StudentModel.builder()
                .id(103)
                .name("麻六")
                .score(BigDecimal.TEN)
                .birthday(LocalDateTime.of(2001,1,1,0,0))
                .build();
        STUDENT_MODELS.add(studentModel1);
        STUDENT_MODELS.add(studentModel2);
        STUDENT_MODELS.add(studentModel3);
        STUDENT_MODELS.add(studentModel4);
    }

    public static void main(String[] args) {
        String sortStr = "score__desc,id__desc";
        List<StudentModel> result = ModelsSortHelper.sort(sortStr, STUDENT_MODELS, StudentModel.class);
        System.out.println("按分数降序,id降序排列如下:");
        System.out.println(result);
        sortStr = "birthday__asc,name__desc";
        result = ModelsSortHelper.sort(sortStr, STUDENT_MODELS, StudentModel.class);
        System.out.println("按生日升序,名字降序排列如下:");
        System.out.println(result);
    }
}

 

posted @ 2020-08-10 12:03  zslm___  阅读(236)  评论(0编辑  收藏  举报