使用注解、反射将列表转换为树

一、添加注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TreeAnno {
    String ID = "id";//主键
    String LEVEL = "level";//层级
    String PID = "pId";//父级主键
    String CHILDREN = "children";//子树

    String SORT_LEVEL = "sorl_level";//记录level的值

    // 保存到map里的key值
    String key();
    // 保存到map里的target值
    String target();
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TreeChildrenAnno {
    String key() default TreeAnno.CHILDREN;
    String target();
}

二、解析注解

import ac.cn.chm.util.CheckUtils;
import ac.cn.chm.util.tree.annotations.TreeAnno;
import ac.cn.chm.util.tree.annotations.TreeChildrenAnno;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class TreeAnalysis {
    public static final String SOURCE = "source";
    public static final String TARGET = "target";
    public static Map<String, Map<String, Map<String, String>>> treeMap = new HashMap<>();
//    {//map
//        Menu:{//map
//            source:{//map
//
//            },target:{
//
//            }
//        },...
//    }

    public static <T> Map<String, Map<String, String>> analysis(Class<T> t) {
        if (CheckUtils.isNotEmpty(t) && treeMap.containsKey(t.toString())) {
            return treeMap.get(t.toString());
        } else {
            return getSourceAndTarget(t);
        }

    }

    public static <T> Map<String, String> source(Class<T> t) {
        if (CheckUtils.isNotEmpty(t) && treeMap.containsKey(t.toString())) {
            return treeMap.get(t.toString()).get(SOURCE);
        } else {
            Map<String, Map<String, String>> tree = getSourceAndTarget(t);
            return CheckUtils.isNotEmpty(tree) ? tree.get(SOURCE) : null;
        }
    }

    public static <T> Map<String, String> target(Class<T> t) {
        if (CheckUtils.isNotEmpty(t) && treeMap.containsKey(t.toString())) {
            return treeMap.get(t.toString()).get(TARGET);
        } else {
            Map<String, Map<String, String>> tree = getSourceAndTarget(t);
            return CheckUtils.isNotEmpty(tree) ? tree.get(TARGET) : null;
        }
    }

    public static <T> String getLevel(Class<T> t) {
        if (CheckUtils.isNotEmpty(t) && !treeMap.containsKey(t.toString())) {
            Map<String, Map<String, String>> tree = getSourceAndTarget(t);
            if (CheckUtils.isEmpty(tree)) {
                return null;
            }
//            else{//在下面执行了
//                tree.get(TARGET).get(TreeAnno.LEVEL);
//            }
        }
        return treeMap.get(t.toString()).get(TARGET).get(TreeAnno.LEVEL);
    }

    private static <T> Map<String, Map<String, String>> getSourceAndTarget(Class<T> t) {
        Map<String, String> source = new HashMap<>();
        Map<String, String> target = new HashMap<>();
        Field[] fields = null;
        fields = t.getDeclaredFields();//获取所有的字段
        try {
            for (Field f : fields
            ) {
                Annotation[] annotations = t.getDeclaredField(f.getName()).getAnnotations();
                for (Annotation a : annotations
                ) {
                    if (a instanceof TreeAnno) {
                        //注解是对的,添加到指定源及目标中
                        TreeAnno ta = (TreeAnno) a;
                        source.put(ta.key(), f.getName());
                        target.put(ta.key(), ta.target());
                    }
                }
            }

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        //校验是否有id,pid,level这三个属性
        if (checkField(source) && checkField(target)) {//还是说自动补齐呢?
            target.put(TreeAnno.CHILDREN, getChildren(t));

            Map<String, Map<String, String>> tree = new HashMap<>();
            tree.put(SOURCE, source);
            tree.put(TARGET, target);
            treeMap.put(t.toString(), tree);
            return tree;
        } else {
            //抛异常
        }
//        annotations = t.
        return null;
    }

    public static <T> String getChildren(Class<T> t) {
        Annotation a = t.getAnnotation(TreeChildrenAnno.class);

        //这里还没有成功
        String children = a == null ? TreeAnno.CHILDREN : ((TreeChildrenAnno) a).target();
        return children.isEmpty() || children == "" ? TreeAnno.CHILDREN : children;
    }

    /**
     * 校验是否拥有id,pId,level这三个属性
     *
     * @param map
     * @return
     */
    private static boolean checkField(Map<String, String> map) {
        boolean existId = false, existPId = false, existLevel = false;// existChildren = false;
        for (String key : map.keySet()) {
            switch (key) {
                case TreeAnno.ID:
                    existId = true;
                    break;
                case TreeAnno.PID:
                    existPId = true;
                    break;
                case TreeAnno.LEVEL:
                    existLevel = true;
                    break;
//                case TreeAnno.CHILDREN:
//                    existChildren = true;
//                    break;
                default:
            }
        }
        return existId && existLevel && existPId;//&& existChildren;
    }

}

三、公用的校验方法及转换工具

import java.util.*;

public class CheckUtils {

    public static void main(String[] args) {
        double[] a = new double[0];
        System.out.println(isEmpty(a));

//        System.out.println("list="+isEmpty(new ArrayList<String>()));
//        System.out.println("list="+isEmpty(new HashSet<String>()));
    }

    public static boolean isEmpty(Object o) {
        if (o == null) {
            return true;
        } else {
            if (o instanceof String && o.toString().trim().equals("")) {        //字符串判断
                return true;
            } else if (o instanceof Iterable && ((Collection) o).size() <= 0) { //判断set和list
                return true;
            } else if (o instanceof Map && ((Map) o).size() == 0) {             //map判断
                return true;
            } else if (o instanceof Object[] && ((Object[]) ((Object[]) o)).length == 0) {//object判断
                return true;
            } else if (isEmptyBasicDataArray(o)) {              //基础数据类型数组判断
                return true;
            }
            return false;
        }
    }
    /**
     * 判断传入所有可变参数是否有一个为空
     * @param o
     * @return
     */
    public static boolean isOneEmpty(Object ... o){
        for (Object obj :o ) {
            if(isEmpty(obj)){//有一个为空,符合条件
                return true;
            }
        }
        return false;
    }

    /**
     * 判断传入所有可变参数是否都为空
     * @param o
     * @return
     */
    public static boolean isAllEmpty(Object ... o){
        for (Object obj :o ) {
            if(!isEmpty(obj)){//有一个不为空,则不符合条件
                return false;
            }
        }
        return true;
    }

    /**
     * 判断传入可变参数是否有一个参数不为空
     * @param o
     * @return
     */
    public static boolean isOneNotEmpty(Object ... o){
        for (Object obj :o ) {
            if(!isEmpty(obj)){//有一个不为空,符合条件
                return true;
            }
        }
        return false;
    }

    /**
     * 判断传入所有可变参数是否都非空
     * @param o
     * @return
     */
    public static boolean isAllNotEmpty(Object ... o){
        for (Object obj :o ) {
            if(isEmpty(obj)){//有一个为空,则不符合条件
                return false;
            }
        }
        return true;
    }
    /**
     * 判断基础数据类型是否非空
     * @param o
     * @return
     */
    public static boolean isNotEmpty(Object o ){
        return !isEmpty(o);
    }

    /**
     * 校验基础数据类型数组是否为空
     *
     * @param o
     * @return
     */
    public static boolean isEmptyBasicDataArray(Object o) {
        if (o == null) {
            return true;
        } else {
            if (o instanceof int[] && ((int[]) ((int[]) o)).length == 0) {
                return true;
            } else if (o instanceof long[] && ((long[]) ((long[]) o)).length == 0) {
                return true;
            } else if (o instanceof byte[] && ((byte[]) ((byte[]) o)).length == 0) {
                return true;
            } else if (o instanceof char[] && ((char[]) ((char[]) o)).length == 0) {
                return true;
            } else if (o instanceof double[] && ((double[]) ((double[]) o)).length == 0) {
                return true;
            } else if (o instanceof float[] && ((float[]) ((float[]) o)).length == 0) {
                return true;
            } else if (o instanceof short[] && ((short[]) ((short[]) o)).length == 0) {
                return true;
            } else if (o instanceof boolean[] && ((boolean[]) ((boolean[]) o)).length == 0) {
                return true;
            }
        }
        return false;
    }


    /**
     * 判断基础数据类型数组是否非空
     * @param o
     * @return
     */
    public static boolean isNotEmptyBasicDataArray(Object o){
        return !isEmptyBasicDataArray(o);
    }

    /**
     * 判断传入可变数组是否有一个为空
     * @param o
     * @return
     */
    public static boolean isOneEmptyBasicDataArray(Object ... o){
        for (Object obj :o ) {
            if(isEmptyBasicDataArray(obj)){//有一个符合条件即可
                return true;
            }
        }
        return false;
    }
    /**
     * 判断传入可变数组是否有一个非空
     * @param o
     * @return
     */
    public static boolean isOneNotEmptyBasicDataArray(Object ... o){
        for (Object obj :o ) {
            if(!isEmptyBasicDataArray(obj)){//有一个符合条件即可
                return true;
            }
        }
        return false;
    }

    /**
     * 判断传入可变数组是否全部为空
     * @param o
     * @return
     */
    public static boolean isAllEmptyBasicDataArray(Object ... o){
        for (Object obj :o ) {
            if(!isEmptyBasicDataArray(obj)){//有一个不为空,则不符合条件
                return false;
            }
        }
        return true;
    }
    /**
     * 判断传入可变数组是否全部为空
     * @param o
     * @return
     */
    public static boolean isAllNotEmptyBasicDataArray(Object ... o){
        for (Object obj :o ) {
            if(isEmptyBasicDataArray(obj)){//有一个不为空,则不符合条件
                return false;
            }
        }
        return true;
    }
}


import ac.cn.chm.util.tree.TreeAnalysis;
import ac.cn.chm.util.tree.TreeNodes;
import ac.cn.chm.util.tree.TreeUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class FormatUtils {

    /**
     * 获取 yyyy-MM-dd HH:mm:ss 格式的时间
     **/
    public static final SimpleDateFormat SDF_DATE = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    /**
     * 获取 yyyy-MM-dd 格式的时间
     **/
    public static final SimpleDateFormat SDF_DAY = new SimpleDateFormat("yyyy-MM-dd");
    /**
     * 获取 HH:mm:ss 格式的时间
     **/
    public static final SimpleDateFormat SDF_TIME = new SimpleDateFormat("HH:mm:ss");
    /**
     * 获取 yyyy-MM-dd HH:mm:ss.SSS 格式的时间
     **/
    public static final SimpleDateFormat SDF_NOW = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    /**
     * 获取 yyyy-MM 格式的时间
     **/
    public static final SimpleDateFormat SDF_MONTH = new SimpleDateFormat("yyyy-MM");
    /**
     * 获取 yyyy 格式的时间
     **/
    public static final SimpleDateFormat SDF_YEAR = new SimpleDateFormat("yyyy");
    /**
     * 获取 HH:mm 格式的时间
     **/
    public static final SimpleDateFormat SDF_CURRENT_DATE = new SimpleDateFormat("HH:mm");


    /**
     * 使用fastJson,但是效率并不高
     *
     * @param date
     * @param format
     * @return
     */
    @Deprecated
    public static String data2JsonStr(Date date, String format) {
        if (CheckUtils.isEmpty(format)) {
            return JSON.toJSONStringWithDateFormat(date, format);
        } else {
            return "";
        }
    }

    /**
     * 按照参数format的格式,日期转字符串
     *
     * @param date
     * @param format
     * @return
     */
    public static String date2Str(Date date, String format) {
        String str = null;
        if (CheckUtils.isNotEmpty(date) && CheckUtils.isNotEmpty(format)) {
            try {
                switch (format) {//优化效率,使用常量,多次使用不需要重新初始化
                    //常用的要放在前面,提高效率
                    case "yyyy-MM-dd HH:mm:ss":
                        str = SDF_DATE.format(date);
                        break;
                    case "yyyy-MM-dd":
                        str = SDF_DAY.format(date);
                        break;
                    case "HH:mm:ss":
                        str = SDF_TIME.format(date);
                        break;
                    case "yyyy-MM-dd HH:mm:ss.SSS":
                        str = SDF_NOW.format(date);
                        break;
                    case "yyyy-MM":
                        str = SDF_MONTH.format(date);
                        break;
                    case "yyyy":
                        str = SDF_YEAR.format(date);
                        break;
                    case "HH:mm":
                        str = SDF_CURRENT_DATE.format(date);
                        break;
                    default:
                        str = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
                }
            } catch (Exception e) {
                e.printStackTrace();
                str = "";
            }
        }
        return str;
    }

    /**
     * 按照yyyy-MM-dd HH:mm:ss的格式,日期转字符串(可以使用dateUtil工具类)
     *
     * @param date
     * @return yyyy-MM-dd HH:mm:ss
     */
//    @Deprecated
    public static String date2Str(Date date) {
        if (CheckUtils.isEmpty(date)) return null;
        return date2Str(date, "yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 将指定格式的字符串转为时间对象
     *
     * @param str
     * @param format
     * @return 失败返回当前时间
     */
    public static Date str2Date(String str, String format) {
        if (CheckUtils.isOneEmpty(str, format)) {
            return null;
        }
        Date date;
        try {
            switch (format) {//优化效率,使用常量,多次使用不需要重新初始化
                //常用的要放在前面,提高效率
                case "yyyy-MM-dd HH:mm:ss":
                    date = SDF_DATE.parse(str);
                    break;
                case "yyyy-MM-dd":
                    date = SDF_DAY.parse(str);
                    break;
                case "HH:mm:ss":
                    date = SDF_TIME.parse(str);
                    break;
                case "yyyy-MM-dd HH:mm:ss.SSS":
                    date = SDF_NOW.parse(str);
                    break;
                case "yyyy-MM":
                    date = SDF_MONTH.parse(str);
                    break;
                case "yyyy":
                    date = SDF_YEAR.parse(str);
                    break;
                case "HH:mm":
                    date = SDF_CURRENT_DATE.parse(str);
                    break;
                default:
                    date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(str);
            }
        } catch (ParseException e) {
            e.printStackTrace();
            date = new Date();
        } catch (Exception e) {
            e.printStackTrace();
            date = new Date();
        }
        return date;
    }

    /**
     * 将yyyy-MM-dd HH:mm:ss格式的字符串转换为时间对象
     *
     * @param str
     * @return 失败返回当前时间
     */
    public static Date str2Date(String str) {
        return str2Date(str, "yyyy-MM-dd HH:mm:ss");
    }


    /**
     * 将对象转换为map
     *
     * @param t
     * @param <T>
     * @return
     */
    public static <T> Map<String, Object> object2Map(T t) {
        return CheckUtils.isEmpty(t) ? new HashMap() : entity2Json(t);
    }

    /**
     * 将对象转换为json
     *
     * @param t
     * @param <T>
     * @return
     */
    public static <T> JSONObject entity2Json(T t) {
        return CheckUtils.isEmpty(t) ? new JSONObject() : (JSONObject) JSONObject.toJSON(t);
    }

    /**
     * json字符串转json对象
     *
     * @param str
     * @return
     */
    public static JSONObject str2Json(String str) {
//        return CheckUtils.isEmpty(str)?new JSONObject():(JSONObject)JSONObject.parse(str);
        if (CheckUtils.isEmpty(str)) new JSONObject();
        try {
            return (JSONObject) JSONObject.parse(str);
        } catch (Exception e) {
            e.printStackTrace();
            return new JSONObject();
        }
    }

    /**
     * json字符串转map
     *
     * @param str
     * @return
     */
    public static Map<String, Object> str2Map(String str) {
        return CheckUtils.isEmpty(str) ? new HashMap<>() : str2Json(str);
    }

    /**
     * json字符串转换对象list
     *
     * @param str   list-json格式字符串
     * @param clazz 要拷贝的类型
     * @param <T>   拷贝的类型
     * @return
     */
    public static <T> List<T> str2List(String str, Class<T> clazz) {
        return CheckUtils.isOneEmpty(str, clazz) ? new ArrayList<T>() : JSONArray.parseArray(str, clazz);
    }

    /**
     * Map转JSONObject(应该是用不上的,但依旧添加,使功能完善)
     *
     * @param map
     * @return
     */
    public static JSONObject map2Json(Map<String, Object> map) {
        return new JSONObject(map);
    }

    /**
     * json字符串转对象
     *
     * @param str   要转换的json格式字符串
     * @param clazz 要转换的对象类型
     * @param <T>   要转换的对象实体泛型
     * @return
     */
    public static <T> T str2Entity(String str, Class<T> clazz) {
        return CheckUtils.isEmpty(str) ? null : objectClone(str, clazz);
    }

    /**
     * 通过反射进行对象拷贝(支持json,map,object)
     *
     * @param vs    源list
     * @param clazz 要拷贝的类型
     * @param <T>   拷贝的类型
     * @param <V>   源类型
     * @return
     */
    public static <T, V> T objectClone(V v, Class<T> clazz) {
        if (CheckUtils.isOneEmpty(v, clazz)) return null;
        try {
            return JSON.parseObject(v instanceof String ? (String) v : JSON.toJSONString(v), clazz);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 对象list拷贝
     *
     * @param vs    源list
     * @param clazz 要拷贝的类型
     * @param <T>   拷贝的类型
     * @param <V>   源类型
     * @return
     */
    public static <T, V> List<T> listClone(List<V> vs, Class<T> clazz) {
        if (CheckUtils.isOneEmpty(vs, clazz)) return new ArrayList<T>();
        try {
            return JSONArray.parseArray(JSON.toJSONString(vs), clazz);
        } catch (Exception e) {
            e.printStackTrace();
            return new ArrayList<T>();
        }
    }

    /**
     * 将json格式的字符串转换为指定对象的列表
     *
     * @param str
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> List<T> listClone(String str, Class<T> clazz) {
        return str2List(str, clazz);
    }

    /**
     * 获取列表里的指定key,并转换为指定格式List,如List<User>-->获取userId-->List<Long> userIds
     *
     * @param vs    源列表
     * @param clazz 获取key的格式
     * @param key   对象中的某一个字段名称
     * @param <T>   key的对象类型
     * @param <V>   源数据对象类型
     * @return
     */
    public static <T, V> List<T> listClone(List<V> vs, Class<T> clazz, String key) {
        List<JSONObject> list = JSONArray.parseArray(JSON.toJSONString(vs), JSONObject.class);
        List<T> ts = new ArrayList<>();
        for (JSONObject obj : list) {
            try {
                ts.add((T) obj.get(key));
            } catch (Exception e) {
                return new ArrayList<T>();
            }
        }
        return ts;
    }

    /**
     * 根据注解获取包含指定key的树
     *
     * @param vs  要转换为树的list集合
     * @param t   从哪个实体类中获取注解
     * @param <T> list集合的实体类
     * @param <V> 需要获取注解的实体类
     * @return
     */
    public static <T, V> List<TreeNodes> list2TreeByAnno(List<V> vs, Class<T> t) {
        return TreeUtils.formatTreeByMap(vs, TreeAnalysis.source(t), TreeAnalysis.target(t));
    }

    /**
     * 将列表转换为树,不去除多余的key值
     *
     * @param vs            要转换为树的list集合
     * @param t             从哪个实体类中获取注解
     * @param <T>list集合的实体类
     * @param <V>需要获取注解的实体类
     * @return
     */
    public static <T, V> List<TreeNodes> list2Tree(List<V> vs, Class<T> t) {
        return TreeUtils.formatTree(vs, TreeAnalysis.source(t), TreeAnalysis.target(t));
    }

    /**
     * 将前端保存的数据转换为实体类数据
     *
     * @param list  源数据
     * @param clazz 从哪个实体类中获取注解
     * @param <T>   list集合的实体类
     * @param <K>   需要获取注解的实体类
     * @return
     */
    public static <T, K> List<K> listCloneChangeKey(List<T> list, Class<K> clazz) {
        List<TreeNodes> tree = TreeUtils.formatList(list, TreeAnalysis.target(clazz), TreeAnalysis.source(clazz));//source与target位置交换,达到反向替换的目的
        return listClone(tree, clazz);
    }

    /**
     * 将列表转换为树
     *
     * @param t   实体类数据
     * @param <T> 列表的实体类泛型
     * @return
     */
    public static <T, K> TreeNodes bean2Nodes(T t, Map<String, String> source, Class<K> clazz) {
        return TreeUtils.formatBean(t, TreeAnalysis.source(clazz), TreeAnalysis.target(clazz));
    }

    /**
     * 将指定的对象转换为相应的实体类
     *
     * @param t     源数据
     * @param clazz 从哪个实体类中获取注解
     * @param <T>   要转换的实体类
     * @param <K>   需要获取注解的实体类
     * @return
     */
    public static <T, K> K objectCloneChangeKey(T t, Class<K> clazz) {
        TreeNodes nodes = TreeUtils.formatBean(t, TreeAnalysis.target(clazz), TreeAnalysis.source(clazz));//source与target位置交换,达到反向替换的目的
        return objectClone(nodes, clazz);
    }
}

四、树的实体


import ac.cn.chm.util.CheckUtils;
import ac.cn.chm.util.tree.annotations.TreeAnno;
import java.util.*;
import java.util.List;

/**
 * 通用列表转换为树类
 */
public class TreeNodes extends HashMap implements Comparable<TreeNodes> {//实现Comparable接口,实现根据level排序

//    private static String targetLevel = TreeAnno.LEVEL;//获取顺序的level值//多线程会炸的吧


    /**
     * 获取子树
     *
     * @param children 子树的key值
     * @return
     */
    public List<TreeNodes> getChildren(String children) {
        if (!this.containsKey(children) || CheckUtils.isEmpty(this.get(children))) {//如果不存在
            this.put(children, new ArrayList<TreeNodes>());
        }
        return (List<TreeNodes>) this.get(children);
    }

    /**
     * 获取int型数据
     *
     * @param key
     * @return
     */
    public Integer getInt(String key) {
        Object o = this.get(key);
        if (o instanceof Integer || o instanceof Short || o instanceof Long || o instanceof Byte) {
            return (Integer) o;
        } else {
            try {
                return Integer.valueOf((String) o);
            } catch (NullPointerException ne) {
                System.out.println("level字段为空");
            } catch (Exception e) {
//                e.printStackTrace();
                System.out.println("level字段为无法转换为整型数字");
            }
        }
        return null;//不会到这来,会先抛异常
    }

    /**
     * 获取string型数据
     *
     * @param key
     * @return
     */
    public String getStr(String key) {
        Object o = this.get(key);
        if (o instanceof Integer || o instanceof Short || o instanceof Long || o instanceof Byte) {
            return String.valueOf(o);
        } else {
            return (String) o;
        }
    }


    @Override
    public int compareTo(TreeNodes tn) {
        //如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
        //1排在当前的后面//-1排在当前的前面
        int big = 1, small = -1, eq = 0;
        if (CheckUtils.isEmpty(tn)) {
            return big;
        }
        Integer thisLevel = this.getInt(this.getStr(TreeAnno.SORT_LEVEL));
        Integer tnLevel = tn.getInt(tn.getStr(TreeAnno.SORT_LEVEL));
        if (CheckUtils.isEmpty(tnLevel)) {
            return big;
        } else if (CheckUtils.isEmpty(thisLevel)) {
            return small;
        } else if (tnLevel < thisLevel) {
            return big;
        } else if (tnLevel > thisLevel) {
            return small;
        }
        return eq;
    }
}

五、树的转换工具


import ac.cn.chm.util.CheckUtils;
import ac.cn.chm.util.FormatUtils;
import ac.cn.chm.util.tree.annotations.TreeAnno;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.util.*;

public class TreeUtils {
    /**
     * 将实体类型转换为指定key值的map
     *
     * @param t      树的内容,需要按照level从小到大进行排序,否则无法获取到第一个层级,且易造成树的分支丢失
     * @param source 未更新前的字段集合
     * @param target 更新后的字段集合
     * @param <T>    要进行数据字段更新的数据类型
     * @return
     */
    public static <T> TreeNodes formatBean(T t, Map<String, String> source, Map<String, String> target) {
        if (CheckUtils.isOneEmpty(t, source, target)) {
            return new TreeNodes();
        }
        String json = JSON.toJSONString(t);
        try {
            return getNodesBytarger(JSON.parseObject(json), source, target);
        } catch (Exception e) {
            return new TreeNodes();
        }
    }

    /**
     * 按map对列表进行数据拷贝操作
     *
     * @param list   要进行拷贝的列表数据集合
     * @param source 未更新前的字段集合
     * @param target 更新后的字段集合
     * @param <T>    要进行数据字段更新的数据类型
     * @return
     */
    public static <T> List<TreeNodes> formatList(List<T> list, Map<String, String> source, Map<String, String> target) {
        if (CheckUtils.isOneEmpty(list, source, target)) {
            return new ArrayList<>();
        }
        try {
            return getCurrencyTreeNodes(list, source, target);//保存多余的字段
        } catch (Exception e) {
            return new ArrayList<>();
        }
    }

    /**
     * 将指定实体转换为map
     *
     * @param list   树的内容,需要按照level从小到大进行排序,否则无法获取到第一个层级,且易造成树的分支丢失
     * @param source 未更新前的字段集合
     * @param target 更新后的字段集合
     * @param <T>    要进行数据字段更新的数据类型
     * @return
     */
    public static <T> List<TreeNodes> formatListByMap(List<T> list, Map<String, String> source, Map<String, String> target) {
        if (CheckUtils.isOneEmpty(list, source, target)) {
            return new ArrayList<>();
        }
        try {
            return getCurrencyTreeNodesByMap(list, source, target);//不保存多余的字段
//            return getCurrencyTreeNodes(list, source, target);//保存多余的字段
        } catch (Exception e) {
            return new ArrayList<>();
        }
    }

    /**
     * 将列表转换为树
     *
     * @param list   树的内容,需要按照level从小到大进行排序,否则无法获取到第一个层级,且易造成树的分支丢失
     * @param source 未更新前的字段集合
     * @param target 更新后的字段集合
     * @param <T>    要进行数据字段更新的数据类型
     * @return
     */
    public static <T> List<TreeNodes> formatTree(List<T> list, Map<String, String> source, Map<String, String> target) {
        if (list == null || list.size() <= 0) {
            return new ArrayList<>();
        }

        List<TreeNodes> treeNodes = formatList(list, source, target);

        Collections.sort(treeNodes);//排序//排序是肯定要的啊

        return list2Tree(treeNodes, source, target);
    }

    /**
     * 按map里的字段将列表转换为树
     *
     * @param list   树的内容,需要按照level从小到大进行排序,否则无法获取到第一个层级,且易造成树的分支丢失
     * @param source 未更新前的字段集合
     * @param target 更新后的字段集合
     * @param <T>    要进行数据字段更新的数据类型
     * @return
     */
    public static <T> List<TreeNodes> formatTreeByMap(List<T> list, Map<String, String> source, Map<String, String> target) {
        if (list == null || list.size() <= 0) {
            return new ArrayList<>();
        }

        List<TreeNodes> treeNodes = formatListByMap(list, source, target);

        Collections.sort(treeNodes);//排序//排序是肯定要的啊

        return list2Tree(treeNodes, source, target);
    }

    /**
     * 将已处理好格式的列表转换为树
     *
     * @param treeNodes 已转换为treeNodes的数据集合
     * @param source    未更新前的字段集合
     * @param target    更新后的字段集合
     * @return
     */
    public static List<TreeNodes> list2Tree(List<TreeNodes> treeNodes, Map<String, String> source, Map<String, String> target) {
        Map<String, List<TreeNodes>> map = new HashMap<>();//change,修改List为指定的类型
        //转换字段
        List<TreeNodes> root = null;//根目录 //change,修改List为指定的类型

        for (TreeNodes current : treeNodes) {//change,修改List为指定的类型
            {//添加当前元素到指定级别
                String level = current.getStr(target.get(TreeAnno.LEVEL));//change,修改获取层级的方法
                if (!map.containsKey(level)) {//不存在,先添加list
                    map.put(level, new ArrayList<TreeNodes>());//change,修改List为指定的类型
                }
                List<TreeNodes> arr = map.get(level);//当前层级//change,修改List为指定的类型
                arr.add(current);
                current.remove(TreeAnno.SORT_LEVEL);//清除辅助用的字段
                if (root == null) {//表示是第一级
                    root = arr;
                }
            }

            //将当前元素添加到父级的子元素列表里
            {
                List<TreeNodes> parentTree = map.get(String.valueOf(current.getInt(target.get(TreeAnno.LEVEL)) - 1));//change,修改List、获取层级的方法
                if (parentTree == null) {
                    continue;
                }
                for (TreeNodes parent : parentTree) {//change,修改List为指定的类型
                    if (parent.get(target.get(TreeAnno.ID)).equals(current.get(target.get(TreeAnno.PID)))) {//如果找不到父级,则为异常数据,抛弃   //change,修改上下级关联的判断依据
                        parent.getChildren(target.get(TreeAnno.CHILDREN)).add(current);
                        break;
                    }
                }
            }
        }

        return root;
    }

    /**
     * 更新字段
     *
     * @param json   要进行字段更新的字符串
     * @param source 未更新前的字段集合
     * @param target 更新后的字段集合
     * @return
     */
    public static String changeKey(String json, Map<String, String> source, Map<String, String> target) {
        if (CheckUtils.isOneEmpty(json, source, target)) {
            return "";
        }
        for (String key : source.keySet()) {
            json = json.replaceAll(source.get(key), target.get(key));
        }
        return json;
    }

    /**
     * 获取CurrencyTreeNodes,不去除多余字段
     *
     * @param list   要进行字段更新的数据集合
     * @param source 未更新前的字段集合
     * @param target 更新后的字段集合
     * @param <T>    要进行字段更新的数据类型
     * @return
     */
    public static <T> List<TreeNodes> getCurrencyTreeNodes(List<T> list, Map<String, String> source, Map<String, String> target) {

        String jsonStr = JSON.toJSONString(list);
        jsonStr = changeKey(jsonStr, source, target);//change,不改变格式,不需要这段代码,直接删除
        List<TreeNodes> treeNodes = FormatUtils.listClone(jsonStr, TreeNodes.class);//change,不改变格式,不需要这段代码,直接删除
        for (TreeNodes t : treeNodes) {
            t.put(TreeAnno.SORT_LEVEL, target.get(TreeAnno.LEVEL));//保存到常量里方便获取
        }
        return treeNodes;
    }

    /**
     * 根据keys里的字段获取CurrencyTreeNodes
     *
     * @param list   要进行字段更新的数据集合
     * @param source 未更新前的字段集合
     * @param target 更新后的字段集合
     * @param <T>    要进行字段更新的数据类型
     * @return
     */
    public static <T> List<TreeNodes> getCurrencyTreeNodesByMap(List<T> list, Map<String, String> source, Map<String, String> target) {
        if (CheckUtils.isOneEmpty(list, source, target)) {
            return null;
        }
        String json = JSON.toJSONString(list);
        List<JSONObject> objects = FormatUtils.listClone(list, JSONObject.class);
        List<TreeNodes> nodes = new ArrayList<>();
        for (JSONObject t : objects) {
            nodes.add(getNodesBytarger(t, source, target));
        }
        return nodes;
    }

    /**
     * 将JSONObject转换为treeNodes对象
     *
     * @param object json对象
     * @param source json对象的格式
     * @param target treeNodes对象的格式
     * @return
     */
    public static TreeNodes getNodesBytarger(JSONObject object, Map<String, String> source, Map<String, String> target) {
        TreeNodes treeNodes = new TreeNodes();
        for (String key : source.keySet()) {
            treeNodes.put(target.get(key), object.get(source.get(key)));
        }
        treeNodes.put(TreeAnno.SORT_LEVEL, target.get(TreeAnno.LEVEL));//保存到常量里方便获取
        return treeNodes;
    }
}

六、测试
用于测试的实体类



import ac.cn.chm.util.tree.annotations.TreeAnno;
import ac.cn.chm.util.tree.annotations.TreeChildrenAnno;

//@Data
@TreeChildrenAnno(target = "children")//,sort = "level"
public class MenuTestAnno {


    @TreeAnno(key = TreeAnno.ID, target = "id")
    private String menuId;
    @TreeAnno(key = "name", target = "name")
    private String menuName;
    @TreeAnno(key = TreeAnno.LEVEL, target = "level1")
    private String menuLevel;
    @TreeAnno(key = TreeAnno.PID, target = "pId")
    private String parentId;
    @TreeAnno(key = "url", target = "path")
    private String menuUrl;
//    @TreeAnno(key = "icon", target = "icon")
    private String menuIcon;

    public MenuTestAnno(String menuId, String menuName, String menuLevel, String parentId, String menuUrl, String menuIcon) {
        this.menuId = menuId;
        this.menuName = menuName;
        this.menuLevel = menuLevel;
        this.parentId = parentId;
        this.menuUrl = menuUrl;
        this.menuIcon = menuIcon;
    }
//省略getter、setter
}


public class TestTree {
    public static void main(String[] args) {
        List<MenuTestAnno> menu = new ArrayList<>();
        menu.add(new MenuTestAnno("1","菜单1","1","0","http://baidu.com/1","icon-1"));
        menu.add(new MenuTestAnno("2","菜单2","1","0","http://baidu.com/2","icon-2"));
        menu.add(new MenuTestAnno("3","菜单3","3","4","http://baidu.com/3","icon-3"));
        menu.add(new MenuTestAnno("4","菜单4","2","1","http://baidu.com/4","icon-4"));
        menu.add(new MenuTestAnno("5","菜单5","2","2","http://baidu.com/5","icon-5"));
        menu.add(new MenuTestAnno("6","菜单6","3","5","http://baidu.com/6","icon-6"));
        menu.add(new MenuTestAnno("7","菜单7","3","4","http://baidu.com/7","icon-7"));
        menu.add(new MenuTestAnno("8","菜单8","4","7","http://baidu.com/8","icon-8"));
        menu.add(new MenuTestAnno("9","菜单9","4","6","http://baidu.com/9","icon-9"));

        List<TreeNodes> nodes = FormatUtils.list2Tree(menu,MenuTestAnno.class);//保存所有key
        System.out.println(JSON.toJSONString(nodes));
        List<TreeNodes> nodes1 = FormatUtils.list2TreeByAnno(menu,MenuTestAnno.class);//只保留添加了注解的key
        System.out.println(JSON.toJSONString(nodes1));
    }
}

猜你喜欢

转载自blog.csdn.net/qq_25598453/article/details/89451614