一、添加注解
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));
}
}