通用实例列表排序实现


	通用实例列表排序实现
[编程语言教程]

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);
        }
    }
}
hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » 通用实例列表排序实现