mirror of
				https://github.com/continew-org/continew-starter.git
				synced 2025-10-31 10:57:15 +08:00 
			
		
		
		
	refactor(extension/crud): 重构查询树列表功能,增加重载方法,支持构建单个根节点或者多个根节点的树结构
This commit is contained in:
		| @@ -59,15 +59,26 @@ public interface CrudService<L, D, Q, C> { | |||||||
|      */ |      */ | ||||||
|     List<L> list(@Valid Q query, @Valid SortQuery sortQuery); |     List<L> list(@Valid Q query, @Valid SortQuery sortQuery); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 查询树列表(多个根节点) | ||||||
|  |      * | ||||||
|  |      * @param query     查询条件 | ||||||
|  |      * @param sortQuery 排序查询条件 | ||||||
|  |      * @param isSimple  是否为简单树结构(不包含基本树结构之外的扩展字段,简单树(下拉列表)使用全局配置结构,复杂树(表格)使用 @TreeField 局部配置) | ||||||
|  |      * @return 树列表信息 | ||||||
|  |      */ | ||||||
|  |     List<Tree<Long>> tree(@Valid Q query, @Valid SortQuery sortQuery, boolean isSimple); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 查询树列表 |      * 查询树列表 | ||||||
|      * |      * | ||||||
|      * @param query        查询条件 |      * @param query        查询条件 | ||||||
|      * @param sortQuery    排序查询条件 |      * @param sortQuery    排序查询条件 | ||||||
|      * @param isSimple  是否为简单树结构(不包含基本树结构之外的扩展字段,简单树(下拉列表)使用全局配置结构,复杂树(表格)使用 @DictField 局部配置) |      * @param isSimple     是否为简单树结构(不包含基本树结构之外的扩展字段,简单树(下拉列表)使用全局配置结构,复杂树(表格)使用 @TreeField 局部配置) | ||||||
|  |      * @param isSingleRoot 是否为单个根节点 | ||||||
|      * @return 树列表信息 |      * @return 树列表信息 | ||||||
|      */ |      */ | ||||||
|     List<Tree<Long>> tree(@Valid Q query, @Valid SortQuery sortQuery, boolean isSimple); |     List<Tree<Long>> tree(@Valid Q query, @Valid SortQuery sortQuery, boolean isSimple, boolean isSingleRoot); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 查询详情 |      * 查询详情 | ||||||
|   | |||||||
| @@ -27,15 +27,20 @@ import cn.hutool.core.util.ReflectUtil; | |||||||
| import cn.hutool.extra.spring.SpringUtil; | import cn.hutool.extra.spring.SpringUtil; | ||||||
| import com.mybatisflex.core.paginate.Page; | import com.mybatisflex.core.paginate.Page; | ||||||
| import com.mybatisflex.core.query.QueryWrapper; | import com.mybatisflex.core.query.QueryWrapper; | ||||||
|  | import jakarta.el.MethodNotFoundException; | ||||||
| import jakarta.servlet.http.HttpServletResponse; | import jakarta.servlet.http.HttpServletResponse; | ||||||
| import org.springframework.data.domain.Sort; | import org.springframework.data.domain.Sort; | ||||||
|  | import org.springframework.lang.NonNull; | ||||||
| import org.springframework.transaction.annotation.Transactional; | import org.springframework.transaction.annotation.Transactional; | ||||||
| import top.continew.starter.core.constant.StringConstants; | import top.continew.starter.core.constant.StringConstants; | ||||||
|  | import top.continew.starter.core.exception.BusinessException; | ||||||
| import top.continew.starter.core.util.ReflectUtils; | import top.continew.starter.core.util.ReflectUtils; | ||||||
|  | import top.continew.starter.core.util.TreeBuildUtils; | ||||||
| import top.continew.starter.core.util.validation.ValidationUtils; | import top.continew.starter.core.util.validation.ValidationUtils; | ||||||
| import top.continew.starter.data.base.BaseMapper; | import top.continew.starter.data.base.BaseMapper; | ||||||
| import top.continew.starter.data.service.impl.ServiceImpl; | import top.continew.starter.data.service.impl.ServiceImpl; | ||||||
| import top.continew.starter.data.util.QueryWrapperHelper; | import top.continew.starter.data.util.QueryWrapperHelper; | ||||||
|  | import top.continew.starter.excel.util.ExcelUtils; | ||||||
| import top.continew.starter.extension.crud.annotation.TreeField; | import top.continew.starter.extension.crud.annotation.TreeField; | ||||||
| import top.continew.starter.extension.crud.autoconfigure.CrudProperties; | import top.continew.starter.extension.crud.autoconfigure.CrudProperties; | ||||||
| import top.continew.starter.extension.crud.autoconfigure.CrudTreeProperties; | import top.continew.starter.extension.crud.autoconfigure.CrudTreeProperties; | ||||||
| @@ -44,12 +49,14 @@ import top.continew.starter.extension.crud.model.query.PageQuery; | |||||||
| import top.continew.starter.extension.crud.model.query.SortQuery; | import top.continew.starter.extension.crud.model.query.SortQuery; | ||||||
| import top.continew.starter.extension.crud.model.resp.LabelValueResp; | import top.continew.starter.extension.crud.model.resp.LabelValueResp; | ||||||
| import top.continew.starter.extension.crud.model.resp.PageResp; | import top.continew.starter.extension.crud.model.resp.PageResp; | ||||||
| import top.continew.starter.excel.util.ExcelUtils; |  | ||||||
|  |  | ||||||
|  | import java.lang.invoke.MethodHandleProxies; | ||||||
|  | import java.lang.invoke.MethodHandles; | ||||||
| import java.lang.reflect.Field; | import java.lang.reflect.Field; | ||||||
| import java.util.ArrayList; | import java.lang.reflect.Method; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Optional; | import java.util.Optional; | ||||||
|  | import java.util.function.Function; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * CRUD 业务实现基类 |  * CRUD 业务实现基类 | ||||||
| @@ -89,9 +96,14 @@ public class CrudServiceImpl<M extends BaseMapper<T>, T extends BaseIdDO, L, D, | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public List<Tree<Long>> tree(Q query, SortQuery sortQuery, boolean isSimple) { |     public List<Tree<Long>> tree(Q query, SortQuery sortQuery, boolean isSimple) { | ||||||
|  |         return this.tree(query, sortQuery, true, false); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<Tree<Long>> tree(Q query, SortQuery sortQuery, boolean isSimple, boolean isSingleRoot) { | ||||||
|         List<L> list = this.list(query, sortQuery); |         List<L> list = this.list(query, sortQuery); | ||||||
|         if (CollUtil.isEmpty(list)) { |         if (CollUtil.isEmpty(list)) { | ||||||
|             return new ArrayList<>(0); |             return CollUtil.newArrayList(); | ||||||
|         } |         } | ||||||
|         CrudProperties crudProperties = SpringUtil.getBean(CrudProperties.class); |         CrudProperties crudProperties = SpringUtil.getBean(CrudProperties.class); | ||||||
|         CrudTreeProperties treeProperties = crudProperties.getTree(); |         CrudTreeProperties treeProperties = crudProperties.getTree(); | ||||||
| @@ -106,8 +118,29 @@ public class CrudServiceImpl<M extends BaseMapper<T>, T extends BaseIdDO, L, D, | |||||||
|             treeNodeConfig = treeProperties.genTreeNodeConfig(treeField); |             treeNodeConfig = treeProperties.genTreeNodeConfig(treeField); | ||||||
|             rootId = treeField.rootId(); |             rootId = treeField.rootId(); | ||||||
|         } |         } | ||||||
|         // 构建树 |         if (isSingleRoot) { | ||||||
|         return TreeUtil.build(list, rootId, treeNodeConfig, (node, tree) -> { |             // 构建单根节点树 | ||||||
|  |             return TreeUtil.build(list, rootId, treeNodeConfig, (node, | ||||||
|  |                                                                  tree) -> buildTreeField(isSimple, node, tree, treeField)); | ||||||
|  |         } else { | ||||||
|  |             Function<L, Long> getId = createMethodReference(listClass, CharSequenceUtil.genGetter(treeField.value())); | ||||||
|  |             Function<L, Long> getParentId = createMethodReference(listClass, CharSequenceUtil.genGetter(treeField | ||||||
|  |                 .parentIdKey())); | ||||||
|  |             // 构建多根节点树 | ||||||
|  |             return TreeBuildUtils.buildMultiRoot(list, getId, getParentId, treeNodeConfig, (node, | ||||||
|  |                                                                                             tree) -> buildTreeField(isSimple, node, tree, treeField)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 构建树字段 | ||||||
|  |      * | ||||||
|  |      * @param isSimple  是否简单树结构 | ||||||
|  |      * @param node      节点 | ||||||
|  |      * @param tree      树 | ||||||
|  |      * @param treeField 树字段 | ||||||
|  |      */ | ||||||
|  |     private void buildTreeField(boolean isSimple, L node, Tree<Long> tree, TreeField treeField) { | ||||||
|         tree.setId(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.value()))); |         tree.setId(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.value()))); | ||||||
|         tree.setParentId(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.parentIdKey()))); |         tree.setParentId(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.parentIdKey()))); | ||||||
|         tree.setName(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.nameKey()))); |         tree.setName(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.nameKey()))); | ||||||
| @@ -120,7 +153,53 @@ public class CrudServiceImpl<M extends BaseMapper<T>, T extends BaseIdDO, L, D, | |||||||
|             fieldList.forEach(f -> tree.putExtra(f.getName(), ReflectUtil.invoke(node, CharSequenceUtil.genGetter(f |             fieldList.forEach(f -> tree.putExtra(f.getName(), ReflectUtil.invoke(node, CharSequenceUtil.genGetter(f | ||||||
|                 .getName())))); |                 .getName())))); | ||||||
|         } |         } | ||||||
|         }); |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 通过反射创建方法引用,支持在父类中查找方法 | ||||||
|  |      * | ||||||
|  |      * @param clazz      实体类类型 | ||||||
|  |      * @param methodName 方法名 | ||||||
|  |      * @param <T>        实体类类型 | ||||||
|  |      * @param <K>        返回值类型 | ||||||
|  |      * @return Function<T, K> 方法引用 | ||||||
|  |      * @throws IllegalArgumentException 如果参数不合法 | ||||||
|  |      * @throws MethodNotFoundException  如果在类层次结构中找不到指定方法 | ||||||
|  |      */ | ||||||
|  |     @SuppressWarnings("unchecked") | ||||||
|  |     public static <T, K> Function<T, K> createMethodReference(@NonNull Class<T> clazz, @NonNull String methodName) { | ||||||
|  |         Method method = getMethod(clazz, methodName); | ||||||
|  |         try { | ||||||
|  |             // 设置访问权限并返回方法引用 | ||||||
|  |             method.setAccessible(true); | ||||||
|  |             return MethodHandleProxies.asInterfaceInstance(Function.class, MethodHandles.lookup().unreflect(method)); | ||||||
|  |         } catch (Exception e) { | ||||||
|  |             throw new BusinessException("创建方法引用失败: " + clazz.getName() + "." + methodName, e); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取方法(包括父类) | ||||||
|  |      * | ||||||
|  |      * @param clazz      实体类 | ||||||
|  |      * @param methodName 方法名 | ||||||
|  |      * @param <T>        实体类 | ||||||
|  |      * @return 方法 | ||||||
|  |      */ | ||||||
|  |     private static <T> Method getMethod(Class<T> clazz, String methodName) { | ||||||
|  |         Class<?> currentClass = clazz; | ||||||
|  |         Method method = null; | ||||||
|  |         // 查找方法(包括父类) | ||||||
|  |         while (currentClass != null) { | ||||||
|  |             try { | ||||||
|  |                 method = currentClass.getDeclaredMethod(methodName); | ||||||
|  |                 break; | ||||||
|  |             } catch (NoSuchMethodException e) { | ||||||
|  |                 // 继续查找父类 | ||||||
|  |                 currentClass = currentClass.getSuperclass(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return method; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ import cn.hutool.core.collection.CollUtil; | |||||||
| import cn.hutool.core.convert.Convert; | import cn.hutool.core.convert.Convert; | ||||||
| import cn.hutool.core.lang.tree.Tree; | import cn.hutool.core.lang.tree.Tree; | ||||||
| import cn.hutool.core.lang.tree.TreeNodeConfig; | import cn.hutool.core.lang.tree.TreeNodeConfig; | ||||||
|  | import cn.hutool.core.lang.tree.TreeUtil; | ||||||
| import cn.hutool.core.map.MapUtil; | import cn.hutool.core.map.MapUtil; | ||||||
| import cn.hutool.core.text.CharSequenceUtil; | import cn.hutool.core.text.CharSequenceUtil; | ||||||
| import cn.hutool.core.util.ReflectUtil; | import cn.hutool.core.util.ReflectUtil; | ||||||
| @@ -29,10 +30,13 @@ import cn.hutool.extra.spring.SpringUtil; | |||||||
| import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||||||
| import com.baomidou.mybatisplus.core.metadata.IPage; | import com.baomidou.mybatisplus.core.metadata.IPage; | ||||||
| import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||||||
|  | import jakarta.el.MethodNotFoundException; | ||||||
| import jakarta.servlet.http.HttpServletResponse; | import jakarta.servlet.http.HttpServletResponse; | ||||||
| import org.springframework.data.domain.Sort; | import org.springframework.data.domain.Sort; | ||||||
|  | import org.springframework.lang.NonNull; | ||||||
| import org.springframework.transaction.annotation.Transactional; | import org.springframework.transaction.annotation.Transactional; | ||||||
| import top.continew.starter.core.constant.StringConstants; | import top.continew.starter.core.constant.StringConstants; | ||||||
|  | import top.continew.starter.core.exception.BusinessException; | ||||||
| import top.continew.starter.core.util.ClassUtils; | import top.continew.starter.core.util.ClassUtils; | ||||||
| import top.continew.starter.core.util.ReflectUtils; | import top.continew.starter.core.util.ReflectUtils; | ||||||
| import top.continew.starter.core.util.TreeBuildUtils; | import top.continew.starter.core.util.TreeBuildUtils; | ||||||
| @@ -97,25 +101,53 @@ public class CrudServiceImpl<M extends BaseMapper<T>, T extends BaseIdDO, L, D, | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public List<Tree<Long>> tree(Q query, SortQuery sortQuery, boolean isSimple) { |     public List<Tree<Long>> tree(Q query, SortQuery sortQuery, boolean isSimple) { | ||||||
|  |         return this.tree(query, sortQuery, true, false); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<Tree<Long>> tree(Q query, SortQuery sortQuery, boolean isSimple, boolean isSingleRoot) { | ||||||
|         List<L> list = this.list(query, sortQuery); |         List<L> list = this.list(query, sortQuery); | ||||||
|         if (CollUtil.isEmpty(list)) { |         if (CollUtil.isEmpty(list)) { | ||||||
|             return new ArrayList<>(0); |             return CollUtil.newArrayList(); | ||||||
|         } |         } | ||||||
|         CrudProperties crudProperties = SpringUtil.getBean(CrudProperties.class); |         CrudProperties crudProperties = SpringUtil.getBean(CrudProperties.class); | ||||||
|         CrudTreeProperties treeProperties = crudProperties.getTree(); |         CrudTreeProperties treeProperties = crudProperties.getTree(); | ||||||
|         TreeField treeField = listClass.getDeclaredAnnotation(TreeField.class); |         TreeField treeField = listClass.getDeclaredAnnotation(TreeField.class); | ||||||
|  |         TreeNodeConfig treeNodeConfig; | ||||||
|  |         Long rootId; | ||||||
|         // 简单树(下拉列表)使用全局配置结构,复杂树(表格)使用局部配置 |         // 简单树(下拉列表)使用全局配置结构,复杂树(表格)使用局部配置 | ||||||
|         TreeNodeConfig treeNodeConfig = isSimple |         if (isSimple) { | ||||||
|             ? treeProperties.genTreeNodeConfig() |             treeNodeConfig = treeProperties.genTreeNodeConfig(); | ||||||
|             : treeProperties.genTreeNodeConfig(treeField); |             rootId = treeProperties.getRootId(); | ||||||
|         String valueGetter = CharSequenceUtil.genGetter(treeField.value()); |         } else { | ||||||
|         String parentIdKeyGetter = CharSequenceUtil.genGetter(treeField.parentIdKey()); |             treeNodeConfig = treeProperties.genTreeNodeConfig(treeField); | ||||||
|         Function<L, Long> getId = createMethodReference(listClass, valueGetter); |             rootId = treeField.rootId(); | ||||||
|         Function<L, Long> getParentId = createMethodReference(listClass, parentIdKeyGetter); |         } | ||||||
|         // 构建树 |         if (isSingleRoot) { | ||||||
|         return TreeBuildUtils.buildMultiRoot(list, getId, getParentId, treeNodeConfig, (node, tree) -> { |             // 构建单根节点树 | ||||||
|             tree.setId(ReflectUtil.invoke(node, valueGetter)); |             return TreeUtil.build(list, rootId, treeNodeConfig, (node, | ||||||
|             tree.setParentId(ReflectUtil.invoke(node, parentIdKeyGetter)); |                                                                  tree) -> buildTreeField(isSimple, node, tree, treeField)); | ||||||
|  |         } else { | ||||||
|  |             Function<L, Long> getId = createMethodReference(listClass, CharSequenceUtil.genGetter(treeField.value())); | ||||||
|  |             Function<L, Long> getParentId = createMethodReference(listClass, CharSequenceUtil.genGetter(treeField | ||||||
|  |                 .parentIdKey())); | ||||||
|  |             // 构建多根节点树 | ||||||
|  |             return TreeBuildUtils.buildMultiRoot(list, getId, getParentId, treeNodeConfig, (node, | ||||||
|  |                                                                                             tree) -> buildTreeField(isSimple, node, tree, treeField)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 构建树字段 | ||||||
|  |      * | ||||||
|  |      * @param isSimple  是否简单树结构 | ||||||
|  |      * @param node      节点 | ||||||
|  |      * @param tree      树 | ||||||
|  |      * @param treeField 树字段 | ||||||
|  |      */ | ||||||
|  |     private void buildTreeField(boolean isSimple, L node, Tree<Long> tree, TreeField treeField) { | ||||||
|  |         tree.setId(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.value()))); | ||||||
|  |         tree.setParentId(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.parentIdKey()))); | ||||||
|         tree.setName(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.nameKey()))); |         tree.setName(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.nameKey()))); | ||||||
|         tree.setWeight(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.weightKey()))); |         tree.setWeight(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.weightKey()))); | ||||||
|         // 如果构建简单树结构,则不包含扩展字段 |         // 如果构建简单树结构,则不包含扩展字段 | ||||||
| @@ -126,29 +158,54 @@ public class CrudServiceImpl<M extends BaseMapper<T>, T extends BaseIdDO, L, D, | |||||||
|             fieldList.forEach(f -> tree.putExtra(f.getName(), ReflectUtil.invoke(node, CharSequenceUtil.genGetter(f |             fieldList.forEach(f -> tree.putExtra(f.getName(), ReflectUtil.invoke(node, CharSequenceUtil.genGetter(f | ||||||
|                 .getName())))); |                 .getName())))); | ||||||
|         } |         } | ||||||
|         }); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 通过反射创建方法引用 |      * 通过反射创建方法引用,支持在父类中查找方法 | ||||||
|      * |      * | ||||||
|      * @param clazz      实体类类型 |      * @param clazz      实体类类型 | ||||||
|      * @param methodName 方法名 |      * @param methodName 方法名 | ||||||
|      * @param <T>        实体类类型 |      * @param <T>        实体类类型 | ||||||
|      * @param <K>        返回值类型 |      * @param <K>        返回值类型 | ||||||
|      * @return Function<T, K> 方法引用 |      * @return Function<T, K> 方法引用 | ||||||
|  |      * @throws IllegalArgumentException 如果参数不合法 | ||||||
|  |      * @throws MethodNotFoundException  如果在类层次结构中找不到指定方法 | ||||||
|      */ |      */ | ||||||
|     @SuppressWarnings("unchecked") |     @SuppressWarnings("unchecked") | ||||||
|     public static <T, K> Function<T, K> createMethodReference(Class<T> clazz, String methodName) { |     public static <T, K> Function<T, K> createMethodReference(@NonNull Class<T> clazz, @NonNull String methodName) { | ||||||
|         try { |         try { | ||||||
|             Method method = clazz.getDeclaredMethod(methodName); |             Method method = getMethod(clazz, methodName); | ||||||
|             method.setAccessible(true); |             method.setAccessible(true); | ||||||
|             return MethodHandleProxies.asInterfaceInstance(Function.class, MethodHandles.lookup().unreflect(method)); |             return MethodHandleProxies.asInterfaceInstance(Function.class, MethodHandles.lookup().unreflect(method)); | ||||||
|         } catch (Exception e) { |         } catch (Exception e) { | ||||||
|             throw new RuntimeException("Failed to create method reference for " + methodName, e); |             throw new BusinessException("创建方法引用失败:" + clazz.getName() + StringConstants.DOT + methodName, e); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取方法(包括父类) | ||||||
|  |      * | ||||||
|  |      * @param clazz      实体类 | ||||||
|  |      * @param methodName 方法名 | ||||||
|  |      * @param <T>        实体类 | ||||||
|  |      * @return 方法 | ||||||
|  |      */ | ||||||
|  |     private static <T> Method getMethod(Class<T> clazz, String methodName) { | ||||||
|  |         Class<?> currentClass = clazz; | ||||||
|  |         Method method = null; | ||||||
|  |         // 查找方法(包括父类) | ||||||
|  |         while (currentClass != null) { | ||||||
|  |             try { | ||||||
|  |                 method = currentClass.getDeclaredMethod(methodName); | ||||||
|  |                 break; | ||||||
|  |             } catch (NoSuchMethodException e) { | ||||||
|  |                 // 继续查找父类 | ||||||
|  |                 currentClass = currentClass.getSuperclass(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return method; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public D get(Long id) { |     public D get(Long id) { | ||||||
|         T entity = super.getById(id, false); |         T entity = super.getById(id, false); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 书中自有颜如玉
					书中自有颜如玉