java 菜单列表转菜单树

需求中经常遇到菜单列表转菜单树的情况,如果知道顶级菜单的话,有工具类可以使用,还是很方便的,hutool有一个TreeUtil类可以帮我们实现此功能,代码如下:

1.menu对象

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value = "Menu对象", description = "菜单表")
public class Menu implements Serializable {

  private static final long serialVersionUID = 1L;

  @TableId(value = "id", type = IdType.ASSIGN_ID)
  private String id;

  @ApiModelProperty(value = "上级id")
  private String parentId;

  @ApiModelProperty(value = "名称")
  private String name;

  @ApiModelProperty(value = "路径")
  private String url;

  @ApiModelProperty(value = "类型")
  private Integer type;

  @ApiModelProperty(value = "排序")
  private Integer sort;

  @ApiModelProperty(value = "是否删除")
  @TableField("is_deleted")
  @TableLogic
  private Boolean deleted;

  @ApiModelProperty(value = "创建时间")
  @TableField(fill = FieldFill.INSERT)
  private LocalDateTime createTime;

  @ApiModelProperty(value = "更新时间")
  @TableField(fill = FieldFill.INSERT_UPDATE)
  private LocalDateTime updateTime;
}

2.接口需要返回的菜单节点

@ApiModelProperty("菜单")
private List<Tree<String>> menus;

3.调用方法

vo.setMenus(
    TreeUtil.build(
        menus, // 菜单列表
        "", // 顶级菜单的id
        (menu, treeMenu) ->{
          treeMenu.setId(menu.getId()).setParentId(menu.getParentId()).setName(menu.getName());
          treeMenu.putExtra("url", menu.getUrl());
          treeMenu.putExtra("type", menu.getType());
        }));

如果只有菜单列表,不知道顶级菜单,那要怎么转成菜单树呢?这是本文的重点了。但是很少用到是真的。上代码:

1.首先定义菜单树

@Data
@ApiModel("菜单树DTO")
public class MenuTreeDTO implements Serializable {
  private static final long serialVersionUID = 1L;

  @ApiModelProperty(value = "编码")
  private String id;
  @ApiModelProperty(value = "名称")
  private String name;
  @ApiModelProperty(value = "父级编码")
  private String parentId;
  @ApiModelProperty(value = "路由")
  private String url;
  @ApiModelProperty(value = "类型")
  private String type;
  @ApiModelProperty(value = "子集")
  private List<MenuTreeDTO> children;
}

2.转换方法

/**
 * 菜单转菜单树
 * @param menus
 * @return
 */
private static List<MenuTreeDTO> convertMenuTree(List<Menu> menus) {
  // 菜单map
  Map<String, MenuTreeDTO> menuMap = menus.stream().map(menu -> {
      MenuTreeDTO menuTree = BeanUtil.copyProperties(menu, MenuTreeDTO.class);
     return menuTree;
  }).collect(Collectors.toMap(MenuTreeDTO::getId, Function.identity()));
  // 菜单子集map
  HashMap<String, List<MenuTreeDTO>> menuChildMap = new HashMap<>(2);
  menus.forEach(menu -> {
    MenuTreeDTO menuTree = BeanUtil.copyProperties(menu, MenuTreeDTO.class);
    // 找到父级节点,若子级已经在父节点了,跳过,否则加入父节点
    MenuTreeDTO parentMenu = menuMap.get(menu.getParentId());
    if (null != parentMenu) {
      if (CollUtil.isNotEmpty(parentMenu.getChildren())) {
        if (!getHasExist(parentMenu.getChildren(), menuTree.getId())) {
          parentMenu.getChildren().add(menuTree);
        }
      } else {
        parentMenu.setChildren(new ArrayList<MenuTreeDTO>() {{ add(menuTree); }});
      }
      // 如果父节点是别人的子节点,别人的子节点需要重新设置,这也是上方为什么需要判断子节点是否已经存在
      MenuTreeDTO grandMenu = menuMap.get(parentMenu.getParentId());
      if (null != grandMenu) {
        if (CollUtil.isNotEmpty(grandMenu.getChildren())) {
          if (getHasExist(grandMenu.getChildren(), parentMenu.getId())) {
            MenuTreeDTO menuTreeDTO = getMenuTree(grandMenu.getChildren(), parentMenu.getId());
            menuTreeDTO.setChildren(parentMenu.getChildren());
          } else {
            grandMenu.getChildren().add(parentMenu);
          }
        } else {
          grandMenu.setChildren(new ArrayList<MenuTreeDTO>() {{ add(parentMenu); }});
        }
      }
    }
    List<MenuTreeDTO> menuTrees = menuChildMap.get(menu.getParentId());
    if (CollUtil.isNotEmpty(menuTrees)) {
      menuTrees.add(menuTree);
    } else {
      menuChildMap.put(menu.getParentId(), new ArrayList<MenuTreeDTO>() {{ add(menuTree); }});
    }
  });
  // 经过以上处理,有子级的被当成了‘树干’,有的可能是别人的子级,需要从‘树干’上移除掉
  Set<Entry<String, List<MenuTreeDTO>>> entrySet = menuChildMap.entrySet();
  Iterator<Entry<String, List<MenuTreeDTO>>> iterator = entrySet.iterator();
  while (iterator.hasNext()) {
    Entry<String, List<MenuTreeDTO>> entry = iterator.next();
    MenuTreeDTO menuTree = menuMap.get(entry.getKey());
    if (null != menuTree && null != menuMap.get(menuTree.getParentId())) {
      iterator.remove();
    }
  }
  // 修剪掉树叶后,循环输出树【特别注意:如果菜单链断裂,比如应该是A->B->C,但是菜单列表只有A、C,A、C会被当成不相关的元素输出】
  List<MenuTreeDTO> menuTrees = new ArrayList<>();
  menuChildMap.forEach((parendMenuId, menuTreeList) -> {
    MenuTreeDTO menuTree = menuMap.get(parendMenuId);
    if (null != menuTree) {
      menuTrees.add(menuTree);
    }
  });
  return menuTrees;
}

/**
 * 获取菜单
 * @param menuTrees
 * @param menuId
 * @return
 */
private static MenuTreeDTO getMenuTree(List<MenuTreeDTO> menuTrees, String menuId) {
  MenuTreeDTO result = null;
  for(MenuTreeDTO menuTree : menuTrees) {
    if (menuId.equals(menuTree.getId())) {
      result = menuTree;
      break;
    }
  }
  return result;
}

/**
 * 判断是否已存在
 * @param menuTrees
 * @param menuId
 * @return
 */
private static boolean getHasExist(List<MenuTreeDTO> menuTrees, String menuId) {
  List<String> menuIds = menuTrees.stream().map(MenuTreeDTO::getId).collect(Collectors.toList());
  return menuIds.contains(menuId);
}

3.调用转换方法

①.接口出参类型需要修改:

@ApiModelProperty("菜单")
private List<MenuTreeDTO> menus;

②.调用转换方法

vo.setMenus(convertMenuTree(menus));

上面的代码是自己设计,手敲,调试的,肯定有不完善,甚至是错误的地方,欢迎指正。

 

正式测试的时候,脑袋突然灵光一闪,没必要费那么大劲写这个树转化方法啊,循环菜单列表,递归找菜单的父级,直到顶级,然后调用人家提供好的工具类。我了个法克。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java菜单设计和菜单组装可以通过Java Swing框架中的JMenuBar、JMenu、JMenuItem等组件实现。 首先,我们可以通过JMenuBar创建菜单栏,使用JMenu创建菜单,使用JMenuItem创建菜单项。例如: ``` JMenuBar menuBar = new JMenuBar(); JMenu fileMenu = new JMenu("文件"); JMenuItem openMenuItem = new JMenuItem("打开"); JMenuItem saveMenuItem = new JMenuItem("保存"); fileMenu.add(openMenuItem); fileMenu.add(saveMenuItem); menuBar.add(fileMenu); ``` 接下来,我们可以将JMenu组件添加到JMenuBar中,将JMenuItem组件添加到JMenu中,从而将菜单项组装成菜单。例如: ``` JMenuBar menuBar = new JMenuBar(); JMenu fileMenu = new JMenu("文件"); JMenuItem openMenuItem = new JMenuItem("打开"); JMenuItem saveMenuItem = new JMenuItem("保存"); fileMenu.add(openMenuItem); fileMenu.add(saveMenuItem); menuBar.add(fileMenu); JMenu editMenu = new JMenu("编辑"); JMenuItem cutMenuItem = new JMenuItem("剪切"); JMenuItem copyMenuItem = new JMenuItem("复制"); JMenuItem pasteMenuItem = new JMenuItem("粘贴"); editMenu.add(cutMenuItem); editMenu.add(copyMenuItem); editMenu.add(pasteMenuItem); menuBar.add(editMenu); ``` 最后,将JMenuBar组件添加到主窗口中即可显示菜单栏。例如: ``` JFrame frame = new JFrame("菜单栏示例"); frame.setJMenuBar(menuBar); frame.setSize(400, 300); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); ``` 通过这样的方式,我们可以实现Java菜单的设计和菜单组装。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值