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

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

可以参考这篇博客 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数据结构如下

 

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

posted @ 2023-07-16 17:13  一只爱阅读的程序员  阅读(176)  评论(0编辑  收藏  举报