首页 > 编程语言 >Java处理子父级菜单的方式二

Java处理子父级菜单的方式二

时间:2023-07-16 17:22:13浏览次数:41  
标签:菜单 Java 父级 menu childMenu menuParentCode menuCode id

  处理存在子父级关系的数据是写代码的过程中常见的操作,前面讲解过使用递归的方法来做,

可以参考这篇博客 https://www.cnblogs.com/yilangcode/p/16831867.html

今天来聊聊一种新的处理方式。使用List集合多轮遍历,添加子父级菜单信息。

建表SQL

DROP TABLE IF EXISTS `sa_menu`;

CREATE TABLE `sa_menu` (

  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',

  `menu_code` varchar(16) DEFAULT NULL COMMENT '菜单编号',

  `menu_parent_code` varchar(32) DEFAULT NULL COMMENT '菜单上级编号',

  `menu_name` varchar(100) DEFAULT NULL COMMENT '菜单名称',

  `menu_marks` varchar(100) DEFAULT NULL COMMENT '备注',

  `menu_url` varchar(100) DEFAULT NULL COMMENT '菜单路径',

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

数据

INSERT INTO `sa_menu` VALUES ('1', '1', '0', '一级菜单一', '一级菜单一', 'one_level_menu');

INSERT INTO `sa_menu` VALUES ('2', '2', '1', '子菜-1-1', '子菜-1-1', 'child_menu_one');

INSERT INTO `sa_menu` VALUES ('3', '3', '1', '子菜-1-2', '子菜-1-2', 'child_menu_two');

INSERT INTO `sa_menu` VALUES ('4', '4', '0', '一级菜单二', '一级菜单二', 'two_level_menu');

INSERT INTO `sa_menu` VALUES ('5', '5', '4', '子菜单-2-1', '子菜单-2-1', 'child_menu_three');

INSERT INTO `sa_menu` VALUES ('6', '6', '4', '子菜单-2-2', '子菜单-2-2', 'child_menu_four');

INSERT INTO `sa_menu` VALUES ('7', '7', '4', '子菜单-2-3', '子菜单-2-3', 'child_menu_five');

数据如下

 

它们的层级关系如下所示

 

问题是如何构建这样带层级关系的子父级结构的数据呢?经过在实际项目中的

检验,测试,可以使用一种比较简单的方式来处理,下面逐一说明。

构建的菜单类如下

@Data

public class SaMenuPo {

 

    /*

     * 主键ID

     * */

    private int id;

 

    /*

     * 菜单 code

     * */

    private String menuCode;

 

    /*

     * 菜单父 code

     * */

    private String menuParentCode;

 

    /*

     * 菜单名称

     * */

    private String menuName;

 

    /*

     * 备注

     * */

    private String menuRemake;

 

    /*

     * 菜单 url

     * */

    private String menuUrl;

 

    /*

     * 子菜单

     * */

    private List<SaMenuPo> childMenu;

}

 

大致的实现思路如下:

查询数据时,将菜单数据全部取出,按照升序排序,便于处理的菜单数据是按照顺序排列。

遍历集合的时候,每次添加一条菜单数据,则删除该条菜单数据,可以提高效率,到最后的时候

传入的菜单都会被删除。删除后的菜单信息保存到一个新的菜单列表当中,在这个新的菜单列表中

来构建具有子父级关系的菜单信息。需要使用到集合遍历时的迭代器,来进行删除最简单。或者查询时

降序排序,添加时倒着遍历集合,然后添加元素后直接删除即可。

查询方式如下

    <select id="menuTest" resultType="mybatis.po.SaMenuPo">

        SELECT

        t.id,

        t.menu_code menuCode,

        t.menu_parent_code menuParentCode,

        t.menu_name menuName,

        t.menu_marks menuMarks,

        t.menu_url menuUrl

        FROM sa_menu t

        order by t.menu_code asc

    </select>

主要的处理代码如下

private List<SaMenuPo> handlerMenu(List<SaMenuPo> menuPoList){

        List<SaMenuPo> resultList = new ArrayList<>();

        // 首先获取一级菜单,添加一个菜单之后,就删除一个菜单

        Iterator<SaMenuPo> iterator = menuPoList.iterator();

        SaMenuPo tempMenu;

        while (iterator.hasNext()){

            tempMenu = iterator.next();

            // 可以确定的一点是,一级菜单的 menuParentCode 为0

            if("0".equals(tempMenu.getMenuParentCode())){

                // 添加一级菜单

                resultList.add(tempMenu);

                // 删除菜单

                iterator.remove();

            }

        }

 

        // 添加二级菜单

        for(int i = 0; i < resultList.size(); i++){

            List<SaMenuPo> childMenu = new ArrayList<>();

            // 需要重新获取迭代器,因为添加完一次菜单后,原菜单列表menuPoList中总数有变化

            iterator = menuPoList.iterator();

            while (iterator.hasNext()){

                tempMenu = iterator.next();

                // 一级菜单的menuCode为二级菜单的 menuParentCode

                if(resultList.get(i).getMenuCode().equals(tempMenu.getMenuParentCode())){

                    // 添加二级菜单

                    childMenu.add(tempMenu);

                    // 删除二级菜单

                    iterator.remove();

                }

            }

            // 添加完一个一级菜单的所有子菜单,则设置子菜单

            resultList.get(i).setChildMenu(childMenu);

        }

 

        return resultList;

}

返回的JSON数据格式如下

{"responseDate":"Sat Jul 15 11:18:48 CST 2023","status":"SUCCESS","errorCode":"","errorMessage":"","responseBody":[{"id":1,"menuCode":"1","menuParentCode":"0","menuName":"一级菜单一","menuMarks":"一级菜单一","menuUrl":"one_level_menu","childMenu":[{"id":2,"menuCode":"2","menuParentCode":"1","menuName":"子菜单-1-1","menuMarks":"子菜单-1-1","menuUrl":"child_menu_one","childMenu":null},{"id":3,"menuCode":"3","menuParentCode":"1","menuName":"子菜单-1-2","menuMarks":"子菜单-1-2","menuUrl":"child_menu_two","childMenu":null}]},{"id":4,"menuCode":"4","menuParentCode":"0","menuName":"一级菜单二","menuMarks":"一级菜单二","menuUrl":"two_level_menu","childMenu":[{"id":5,"menuCode":"5","menuParentCode":"4","menuName":"子菜单-2-1","menuMarks":"子菜单-2-1","menuUrl":"child_menu_three","childMenu":null},{"id":6,"menuCode":"6","menuParentCode":"4","menuName":"子菜单-2-2","menuMarks":"子菜单-2-2","menuUrl":"child_menu_four","childMenu":null},{"id":7,"menuCode":"7","menuParentCode":"4","menuName":"子菜单-2-3","menuMarks":"子菜单-2-3","menuUrl":"child_menu_five","childMenu":null}]}]}

 

然后去这个网站 https://jsoncrack.com/editor 将返回的数据放在左侧部分,整个JSON数据的结构就会

很清晰的显示出来。页面中拿到数据后再去渲染菜单就会方便很多。

 

 

这里只有两层菜单,处理起来比较方便,只需要处理两次即可。如果有三层呢?那就需要在处理一次,先遍历一级菜单,

然后遍历二级菜单,添加二级菜单的子菜单数据。这时候就可以考虑使用递归来做,代码会更加地简洁,使用更加地方便。

上面的菜单使用递归方式来处理如下,需要拆分为如下的两个方法来处理,这样就可以处理三级,四级菜单;或者是处理子父级

关系的数据比如省-市-区-县数据;或者是其他有子父级关系的数据;或是具有层级关系的数据,比如文件夹、文件数据。

    private List<SaMenuPo> handlerOneLevelMenu(List<SaMenuPo> menuPoList){

        List<SaMenuPo> resultMenu = new ArrayList<>();

        for(SaMenuPo saMenuPo : menuPoList){

            if("0".equals(saMenuPo.getMenuParentCode())){

                // 添加一级菜单

                resultMenu.add(saMenuPo);

            }

        }

 

        for(SaMenuPo saMenuPo : resultMenu){

            recursionHandlerMenu(menuPoList, saMenuPo);

        }

 

        return resultMenu;

    }

 

    private SaMenuPo recursionHandlerMenu(List<SaMenuPo> menuPoList, SaMenuPo parentSaMenuPo){

        List<SaMenuPo> childMenu = new ArrayList<>();

        for(SaMenuPo saMenuPo : menuPoList){

            if(parentSaMenuPo.getMenuCode().equals(saMenuPo.getMenuParentCode())){

                // 有子菜单数据,则递归调用

                recursionHandlerMenu(menuPoList, saMenuPo);

                // 添加子菜单数据

                childMenu.add(saMenuPo);

            }

        }

 

        if(childMenu.size() < 1){

            // 递归调用时,没有子菜单数据,则直接返回

            return parentSaMenuPo;

        }

 

        // 有子菜单数据,则添加子菜单数据

        parentSaMenuPo.setChildMenu(childMenu);

        return parentSaMenuPo;

    }

为了演示方便,这时候添加一条三级菜单数据,如下

INSERT INTO `sa_menu` (`id`, `menu_code`, `menu_parent_code`, `menu_name`, `menu_marks`, `menu_url`) VALUES ('8', '8', '2', '子菜单-3-1', '子菜单-3-1', 'child_menu_six');

然后进行测试,返回数据如下

{"responseDate":"Sat Jul 15 11:55:49 CST 2023","status":"SUCCESS","errorCode":"","errorMessage":"","responseBody":[{"id":1,"menuCode":"1","menuParentCode":"0","menuName":"一级菜单一","menuMarks":"一级菜单一","menuUrl":"one_level_menu","childMenu":[{"id":2,"menuCode":"2","menuParentCode":"1","menuName":"子菜单-1-1","menuMarks":"子菜单-1-1","menuUrl":"child_menu_one","childMenu":[{"id":8,"menuCode":"8","menuParentCode":"2","menuName":"子菜单-3-1","menuMarks":"子菜单-3-1","menuUrl":"child_menu_six","childMenu":null}]},{"id":3,"menuCode":"3","menuParentCode":"1","menuName":"子菜单-1-2","menuMarks":"子菜单-1-2","menuUrl":"child_menu_two","childMenu":null}]},{"id":4,"menuCode":"4","menuParentCode":"0","menuName":"一级菜单二","menuMarks":"一级菜单二","menuUrl":"two_level_menu","childMenu":[{"id":5,"menuCode":"5","menuParentCode":"4","menuName":"子菜单-2-1","menuMarks":"子菜单-2-1","menuUrl":"child_menu_three","childMenu":null},{"id":6,"menuCode":"6","menuParentCode":"4","menuName":"子菜单-2-2","menuMarks":"子菜单-2-2","menuUrl":"child_menu_four","childMenu":null},{"id":7,"menuCode":"7","menuParentCode":"4","menuName":"子菜单-2-3","menuMarks":"子菜单-2-3","menuUrl":"child_menu_five","childMenu":null}]}]}

最终展示的JSON数据结构如下

 

这篇博客就写到这里,如果有其他更好建议的小伙伴,欢迎留言讨论。

标签:菜单,Java,父级,menu,childMenu,menuParentCode,menuCode,id
From: https://www.cnblogs.com/yilangcode/p/17558163.html

相关文章

  • java序列化和反序列化
    感觉网上很多博客对这个的解释实在太官方了,也没说为什么一定要实现序列化接口。去看看rpc框架源码,或者java网络编程或者向磁盘进行序列化就知道了。首先这是个标记接口,就是用来告诉程序某某对象是可序列化对象,像dubbo框架,要传输对象就必须序列化。网络编程已经告诉你了,想要向另......
  • Java性能优化-测试try-catch放在循环内和外的性能对比与业务区别
    场景Java中使用JMH(JavaMicrobenchmarkHarness微基准测试框架)进行性能测试和优化:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/131723751使用如上方式测试Java中try-catch放在循环内和循环外是否有性能上的差别。注:博客:https://blog.csdn.net/badao_lium......
  • 用java写一个逆置单链表
    用Java写一个逆置单链表单链表是一种常见的数据结构,它由一系列节点组成,每个节点包含一个数据元素和一个指向下一个节点的引用。逆置单链表是指将原来的单链表中的节点顺序颠倒过来。在这篇文章中,我们将使用Java来实现逆置单链表的功能。我们将会介绍单链表的基本概念,并给出逆置单......
  • 用java创建一个单链表
    使用Java可以很方便地创建和操作数据结构,其中包括单链表。单链表是一种常见的线性数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。这种数据结构可以用于实现队列、栈、链表等等。在本文中,我们将学习如何使用Java创建一个单链表,并演示一些基本的操作。首先,我......
  • day07 7.1 Java中的面向对象之类与对象
    day077.1Java中的面向对象之类与对象【一】类与对象【1】类定义规范类与对象的关系类是实体对象的概念模型,笼统的,不具体的,比如人类、动物类、鸟类对象又称为实体,类具体化的表现小红/小明小猫一号/小狗一号对象中有属性,有方法不同对象属性是独有的方法是共......
  • JavaScript:将对象数组映射到字典
    JavaScript:将对象数组映射到字典#javascript#打字稿#数据在JavaScript/TypeScript中将对象数组转换为字典的最简单方法:letdata=[{id:1,country:'Germany',population:83623528},{id:2,country:'Austria',population:8975552},{id:3,country......
  • Java性能优化-测试数组和链表在查询和添加删除时性能对比
    场景Java中使用JMH(JavaMicrobenchmarkHarness微基准测试框架)进行性能测试和优化:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/131723751上面在使用JMH时测试了Java中数组和链表在进行头部插入时的对比结果。下面分别对比在头部、中部、尾部分别进行查询和......
  • Java在指定位置添加字符串
    Java在指定位置添加字符串的实现作为一名经验丰富的开发者,我很乐意教会刚入行的小白如何在Java中实现在指定位置添加字符串的操作。在本篇文章中,我将按照以下步骤详细说明整个实现过程:获取原始字符串创建一个StringBuilder对象使用StringBuilder的insert()方法在指定位置插入......
  • Java语言支付代码
    Java语言支付代码引言随着电子商务的迅速发展,支付功能成为了每个电商平台必备的功能之一。在Java语言中,开发者可以使用各种支付SDK和API来实现支付功能。本文将介绍Java语言中支付代码的基本原理,并提供一些示例代码以帮助读者更好地理解。支付流程在介绍具体的支付代码前,我们先......
  • Java项目压测 链接被拒绝
    Java项目压测-链接被拒绝在进行Java项目压测时,有时会遇到“链接被拒绝”的问题。这意味着在压测过程中,无法与目标服务器建立连接。本文将介绍一些可能导致此问题的原因,并提供相应的代码示例来解决这个问题。原因一:服务器资源不足当服务器资源不足时,无法处理大量的并发请求,会导......