实际工作中很多情况会遇到存在层级关系的数据,然后需要处理成树形结构的数据格式,以便提供给前端使用,这里把我工作用实际用到的工具类分享给大家;
核心的思想就是通过Java的反射获取对应的方法和对应属性的值,然后通过递归的方式来完成树形结构数据组装
接下来就是实际开发中用到的工具类代码
首先提供对应的实体类、反射工具类、转换工具类,代码如下:
实体类(需要存在层级关联关系字段):
public class TreeModel {
private String id;
private String name;
private String parentId;
private List<TreeModel> children ;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
public List<TreeModel> getChildren() {
return children;
}
public void setChildren(List<TreeModel> children) {
this.children = children;
}
}
反射工具类:
public class ClassReflectUtils {
public static Map<String, Field> getFieldsMap(Class<? extends Object> clazz) {
Map<String, Field> fieldMap = new HashMap<String, Field>();
Field[] fieldArr = clazz.getDeclaredFields();
for (Field field : fieldArr) {
fieldMap.put(field.getName(), field);
}
Class<?> superClazz = clazz.getSuperclass();
if (null != superClazz) {
Map<String, Field> superFieldMap = getFieldsMap(superClazz);
fieldMap.putAll(superFieldMap);
}
return fieldMap;
}
// 获取某个类(clazz)的某个属性(fieldName)的get方法的值
public static <T> Object getfieldValue(Class<?> clazz, T instance, String fieldName) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Object fieldKeyValue = null;
Method getKeyMethod = ClassReflectUtils.getMethod(clazz, fieldName);
if (null != instance) {
fieldKeyValue = getKeyMethod.invoke(instance);
}
return fieldKeyValue;
}
// 获取某个类(clazz)的某个属性(fieldName)的get方法
public static Method getMethod(Class<? extends Object> clazz, String key) throws NoSuchMethodException {
String nkey = String.valueOf(key.charAt(0)).toUpperCase() + ((key.length() == 1) ? "" : key.substring(1));
Method getKeyMethod = clazz.getDeclaredMethod("get" + nkey);
return getKeyMethod;
}
// 为目标实例的某个属性set值
public static void setValue(Class<? extends Object> clazz, Object instance, String fieldName, Object fieldValue, Class<?> fieldType) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
// logger.info("{}设置{}的值{},值类型:{}", clazz.getName(), fieldName, fieldValue.toString(), fieldType.getName());
Method setChildMethod = ClassReflectUtils.setMethod(clazz, fieldName, fieldType);
setChildMethod.invoke(instance, fieldValue);
}
public static Method setMethod(Class<? extends Object> clazz, String fieldName, Class<?>... fieldClass) throws NoSuchMethodException {
String nkey = String.valueOf(fieldName.charAt(0)).toUpperCase() + ((fieldName.length() == 1) ? "" : fieldName.substring(1));
return clazz.getDeclaredMethod("set" + nkey, fieldClass);
}
}
转换工具类(排序时会用到):
public class TransUtils {
public static Long transDefLong(Object obj) {
try {
Long ln = transLong(obj);
return null == ln ? 0L : ln;
} catch (Exception e) {
return 0L;
}
}
public static Long transLong(Object obj) {
if (null == obj)
return null;
String str = transString(obj);
if (StringUtils.isBlank(str))
return null;
return Long.valueOf(str);
}
/**
* 转换为字符串
*/
public static String transString(Object obj) {
if (null == obj)
return null;
return String.valueOf(obj);
}
}
实际的工具类:
public class TreeUtil {
public final static String ROOT = "";
public final static String KeyCode = "id";
public final static String ParentKeyCode = "parentId";
public final static String Checked = "checked";
public final static String Children = "children";
/**
* @Discription: list格式化树形结构
* @Param dataList 目标集合
* @Param sortFiled 排序字段
*/
public static <T> List<T> toTree(List<T> dataList, String sortFiled) throws Exception {
try {
return buildTree(dataList, ParentKeyCode, KeyCode, ROOT, null, sortFiled);
} catch (Exception e) {
e.printStackTrace();
throw new Exception("树形格式化错误");
}
}
public static <T> List<T> buildTree(List<T> dataList, String parentkey, String key, String parentValue, List<String> selKey, String sortFiled) throws NoSuchFieldException, SecurityException, Exception {
if (CollectionUtils.isEmpty(dataList))
return null;
T t = dataList.get(0);
Class<? extends Object> clazz = t.getClass();
// 判断是否存在字段 判断是否选中
Map<String, Field> filedMap = ClassReflectUtils.getFieldsMap(clazz);
if (null == filedMap.get(parentkey)) {
throw new Exception(clazz.getSimpleName() + "类没有" + parentkey + "字段");
}
if (null == filedMap.get(key)) {
throw new Exception(clazz.getSimpleName() + "类没有" + key + "字段");
}
if (CollectionUtils.isEmpty(selKey))
selKey = new ArrayList<String>();
// 判断父节点数据和传入的参数是否一致
if(null == parentValue){
parentValue = TreeUtil.ROOT;
}
return buildTreeCore(clazz, filedMap, dataList, parentkey, key, parentValue, selKey, sortFiled);
}
private static <T> List<T> buildTreeCore(Class<? extends Object> clazz, Map<String, Field> filedMap, List<T> dataList, String parentkey, String key, String parentValue, List<String> selKey, String sortFiled) throws NoSuchFieldException, SecurityException, Exception {
List<T> treelist = dataList.parallelStream().filter(obj -> {
// 查找子节点,进行过滤
// 获取当前数据节点的父节点数据
try {
String fieldParentValue = (String) ClassReflectUtils.getfieldValue(clazz, obj, parentkey);
if(StringUtils.isBlank(fieldParentValue)){
fieldParentValue = ROOT;
}
return StringUtils.equals(fieldParentValue, parentValue);
} catch (IllegalArgumentException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return false;
}).map(obj -> {
String idValue = null;
// 获取ID数据
try {
idValue = (String) ClassReflectUtils.getfieldValue(clazz, obj, key);
// 判断是否选中
if (null != filedMap.get(Checked) && !CollectionUtils.isEmpty(selKey)) {
String checkedFlag = selKey.contains(idValue) ? "Y" : "N";
// 设置是否选中值
ClassReflectUtils.setValue(clazz, obj, Checked, checkedFlag, String.class);
}
// 查询当前节点子节点
List<T> childs = buildTreeCore(clazz, filedMap, dataList, parentkey, key, idValue, selKey, sortFiled);
//数据排序
if (!CollectionUtils.isEmpty(childs) && StringUtils.isNotBlank(sortFiled)) {
childs.sort(new java.util.Comparator<Object>() {
@Override
public int compare(Object t1, Object t2) {
// 取出权重
Object o1Val;
try {
o1Val = ClassReflectUtils.getfieldValue(clazz, t1, sortFiled);
Object o2Val = ClassReflectUtils.getfieldValue(clazz, t2, sortFiled);
Long o1 = TransUtils.transDefLong(o1Val);
Long o2 = TransUtils.transDefLong(o2Val);
return o1.compareTo(o2);
} catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
return 0;
}
});
}
// 设置子节点数据
ClassReflectUtils.setValue(clazz, obj, Children, childs, List.class);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}).collect(Collectors.toList());
// 数据排序
if (StringUtils.isNotBlank(sortFiled)) {
treelist.sort(new java.util.Comparator<Object>() {
@Override
public int compare(Object t1, Object t2) {
// 取出权重
Object o1Val;
try {
o1Val = ClassReflectUtils.getfieldValue(clazz, t1, sortFiled);
Object o2Val = ClassReflectUtils.getfieldValue(clazz, t2, sortFiled);
Long o1 = TransUtils.transDefLong(o1Val);
Long o2 = TransUtils.transDefLong(o2Val);
return o1.compareTo(o2);
} catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
e.printStackTrace();
}
return 0;
}
});
}
return treelist;
}
}
代码测试:
@Test
void getTree() throws Exception{
List<TreeModel> tree1 = new ArrayList<>();
TreeModel t1 = new TreeModel();
t1.setId("1");
t1.setName("1");
TreeModel t2 = new TreeModel();
t2.setId("2");
t2.setName("2");
TreeModel t3 = new TreeModel();
t3.setId("3");
t3.setName("3");
TreeModel t11 = new TreeModel();
t11.setId("11");
t11.setName("11");
t11.setParentId("1");
TreeModel t12 = new TreeModel();
t12.setId("12");
t12.setName("12");
t12.setParentId("1");
TreeModel t111 = new TreeModel();
t111.setId("111");
t111.setName("111");
t111.setParentId("11");
TreeModel t112 = new TreeModel();
t112.setId("112");
t112.setName("112");
t112.setParentId("11");
tree1.add(t111);
tree1.add(t112);
tree1.add(t11);
tree1.add(t12);
tree1.add(t1);
tree1.add(t2);
tree1.add(t3);
List<TreeModel> treeModels = TreeUtil.toTree(tree1, null);
System.out.println(toJSONString(treeModels));
}
最终输出结果:
image.png
上面测试代码中使用到的toJOSNString()方法如下:
public static ObjectMapper mapper = new ObjectMapper();
public static String toJSONString(Object obj) {
if (null == obj)
return null;
try {
return mapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
共同学习,欢迎一起讨论!