在很多场景中我们需要将list转为多对多的数据结构,然后传给前端:如我们在查询菜单等场景,然而很多情况下不知道数据的层级,无从下手,下面我将我实现的一段代码贴出,供大家参考:
/**
* @Auther: MR.rp
* @Date: 2021/10/28 13:55
* @Description: 树的继承者
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "树的继承父类")
@ToString
public class TreeMode<T> implements Cloneable {
@TableId(value = "id", type = IdType.AUTO)
@ApiModelProperty(value = "id")
private Integer id;
@ApiModelProperty(value = "父id,顶级父id为0")
private Integer pid;
@ApiModelProperty(value = "子集")
private List<? extends TreeMode > children;
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
为简化代码,该代码使用了java8的代码编写,使用了lombok插件简化get,set方法,swagger的注释我也没有去掉,能看懂就行,实体类大家也可以自己写,根据自己的业务,选择继承上面的实体类;
/**
* @Auther: MR.rp
* @Date: 2021/10/28 14:32
* @Description: 将list转换为树形
*/
public class TreeBuilder {
/**
* list转树形结构工具
* @param allNodes
* @return
*/
public static List<? extends TreeMode> treeList(List <? extends TreeMode> allNodes) {
Stream<? extends TreeMode> stream = allNodes.stream().filter(permission -> permission.getPid().equals(0))
.map(permission -> covert(permission, allNodes));
List<? extends TreeMode> result = stream.collect(Collectors.toList());
return result;
}
/**
* 递归查找子树
* @param permission
* @param permissionList
* @return
*/
private static TreeMode<? extends TreeMode> covert(TreeMode<? extends TreeMode > permission, List<? extends TreeMode> permissionList) {
TreeMode<? extends TreeMode> node = (TreeMode<? extends TreeMode>) permission.clone();
Stream<? extends TreeMode> stream = permissionList.stream().filter(subPermission -> subPermission.getPid().equals(permission.getId()))
.map(subPermission -> covert(subPermission, permissionList));
List<? extends TreeMode> children = stream.collect(Collectors.toList());
node.setChildren(children);
return node;
}
}
以上为自己实现的代码,可能存在bug,仅供参考学习,欢迎指正,共同学习进步
在之前的代码虽然实现了转换树形结构,但是用的是Beanutils.copyproperties,似乎对泛型支持不太有好,
在测试中只拷贝了父类的属性,改用了深拷贝的方法,在子类实现的时候需要实现深拷贝的方法;
这里我也贴出自己的业务代码,仅供参考:
/**
* <p>
* 菜单权限表
* </p>
*
* @author MR.RP
* @since 2021-10-29
*/
@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="Menu对象", description="菜单权限表")
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Menu extends TreeMode implements Serializable,Cloneable{
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "路由路径")
private String path;
@ApiModelProperty(value = "路由对应name(英文)")
private String name;
@ApiModelProperty(value = "该路由对应的组件")
private String component;
@ApiModelProperty(value = "重定向的路由地址")
private String redirect;
@ApiModelProperty(value = "排序字段")
private Integer orderNo;
@ApiModelProperty(value = "是否忽略权限")
private String ignoreAuth;
@ApiModelProperty(value = "是否只生成菜单")
private String ignoreRoute;
@ApiModelProperty(value = "是否为单级路由")
private String single;
@ApiModelProperty(value = "权限")
private String permission;
@ApiModelProperty(value = "是否删除")
@TableLogic
private Integer isDel;
@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT)
private String gmtCreate;
@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private String gmtModified;
@ApiModelProperty(value = "菜单组件")
@TableField(exist=false)
private MenuMeta menuMeta;
@Override
public Object clone() {
Menu menu = (Menu)super.clone();
if(menuMeta!= null){
MenuMeta meta =(MenuMeta) menuMeta.clone();
menu.setMenuMeta(menuMeta);
}
return menu;
}
}
下面是属性实体类:
/**
* <p>
* 菜单组件表
* </p>
*
* @author MR.RP
* @since 2021-10-29
*/
@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="MenuMeta对象", description="菜单组件表")
public class MenuMeta implements Serializable,Cloneable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty(value = "菜单id")
private Integer menuId;
@ApiModelProperty(value = "路由名称")
private String title;
@ApiModelProperty(value = "图标")
private String icon;
@ApiModelProperty(value = "是否不显示该菜单")
@TableField("hideMenu")
private String hidemenu;
@ApiModelProperty(value = "是否不在选项卡中显示")
@TableField("hideBreadcrumb")
private String hidebreadcrumb;
@ApiModelProperty(value = "当页面为外部页面时的路径")
@TableField("frameSrc")
private String framesrc;
@ApiModelProperty(value = "是否缓存")
@TableField("ignoreKeepAlive")
private String ignorekeepalive;
@ApiModelProperty(value = "是否为链接")
@TableField("isLink")
private String islink;
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
为了让代码更加通用所以在写util时候用了部分泛型,如果发现有bug欢迎留言,共同学习,
嗯,还在努力学习中…大家有什么建议吗?