通用實例列表排序實現

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);
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章