java实现树形菜单
Posted 今朝花落悲颜色
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java实现树形菜单相关的知识,希望对你有一定的参考价值。
最近要开发一个菜单接口,结构是父菜单下面有子菜单,子菜单下面还有子菜单,要实现树形结构返给前端。
数据表设计
CREATE TABLE `platform_menu` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '菜单id',
`menu_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单名称',
`menu_value` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单值(前端路由)',
`parent_id` bigint NULL DEFAULT NULL COMMENT '上级菜单id',
`parent_path` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单全路径(用/隔开)',
`func_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '功能类型(0菜单1按钮2区块)',
`order_num` int NULL DEFAULT NULL COMMENT '排序',
`icon` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图标',
`created_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
`created_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '创建时间',
`updated_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人',
`updated_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 21 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '菜单信息 ' ROW_FORMAT = Dynamic;
创建树形结构工具类
import cn.hutool.core.collection.CollUtil;
import org.apache.commons.compress.utils.Lists;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @author ws
* @date 2021/9/5
*/
public class BaseTreeHelper {
/**
* @param <T> 节点类型
* @param <E> 节点id的类型
* @return 树形结构列表
* @author ws
* @date 2021/9/5
* 根据所有树节点列表,生成含有所有树形结构的列表
**/
public static <T extends TreeNode<E, T>, E> List<T> generateTrees(List<T> data) {
if (CollUtil.isEmpty(data)) {
return Lists.newArrayList();
}
//将集合中所有数据按照父Id进行分组,放入Map中,Map<parntId, List<T>>
Map<String, List<T>> groupByParentIdMap = data.stream().collect(Collectors.groupingBy(item -> item.root() ? "" : Objects.toString(item.getPid())));
//将集合中所有数据以数据Id为key,放入Map中,Map<id,T>
Map<String, T> dataMap = data.stream().collect(Collectors.toMap(item -> item.getId().toString(), t -> t));
List<T> resp = Lists.newArrayList();
//遍历数据,将子节点放入对应父节点Children属性中
groupByParentIdMap.forEach((parentId, values) -> {
if (dataMap.containsKey(parentId)) {
List<T> child = dataMap.get(parentId).getChildren();
if (CollUtil.isEmpty(child)) {
child = Lists.newArrayList();
}
child.addAll(values);
dataMap.get(parentId).setChildren(child);
} else {
resp.addAll(values);
}
});
return resp;
}
/**
* @param parent 父节点
* @param <T> 实际节点类型
* @return 叶子节点
* @author ws
* @date 2021/9/5
* 获取指定树节点下的所有叶子节点
**/
public static <T extends TreeNode<E, T>, E> List<T> getLeafs(T parent) {
List<T> leafs = new ArrayList<>();
fillLeaf(parent, leafs);
return leafs;
}
/**
* @param parent 父节点
* @param leafs 叶子节点列表
* @param <T> 实际节点类型
* @author ws
* @date 2021/9/5
* 将parent的所有叶子节点填充至leafs列表中
**/
private static <T extends TreeNode<E, T>, E> void fillLeaf(T parent, List<T> leafs) {
List<T> children = parent.getChildren();
// 如果节点没有子节点则说明为叶子节点
if (CollUtil.isEmpty(children)) {
leafs.add(parent);
return;
}
// 递归调用子节点,查找叶子节点
for (T child : children) {
fillLeaf(child, leafs);
}
}
}
创建UserMenusVo对象,里面可以只写需要返回的属性字段就行。
import com.knight.common.core.utils.tree.TreeNode;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author ws
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserMenusVo implements TreeNode<Long, UserMenusVo> {
private static final long serialVersionUID = 1L;
/**
* id
*/
@ApiModelProperty("菜单id")
private Long id;
/**
* 菜单名称
*/
@ApiModelProperty("菜单名称")
private String name;
/**
* 菜单值(前端路由)
*/
@ApiModelProperty("菜单值")
private String menuValue;
/**
* 上级菜单id
*/
@ApiModelProperty("上级菜单")
private Long pid;
/**
* 菜单全路径(用/隔开)
*/
@ApiModelProperty("菜单全路径")
private String parentPath;
/**
* 功能类型(0菜单1按钮2区块)
*/
@ApiModelProperty("功能类型")
private String funcType;
/**
* 排序
*/
@ApiModelProperty("排序")
private Integer orderNum;
/**
* 图标
*/
@ApiModelProperty("图标")
private String icon;
@ApiModelProperty("子菜单")
private List<UserMenusVo> children;
@Override
@ApiModelProperty("父节点")
public Boolean root() {
return pid == null;
}
}
controller,返回的pid就是parentId。
public Result<List<UserMenusVo>> listMenuAll() {
//查询所有菜单
List<UserMenusVo> menus = this.listMenuAll();
//返回树形结构
return Result.ok(BaseTreeHelper.generateTrees(menus));
}
以上是关于java实现树形菜单的主要内容,如果未能解决你的问题,请参考以下文章