Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 303|回复: 0

[默认分类] Java构建网站多级菜单功能解决方案

[复制链接]
  • TA的每日心情
    开心
    2021-12-13 21:45
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    发表于 2020-8-14 09:52:49 | 显示全部楼层 |阅读模式


      在网站开发的时候我们会对网站的栏目进行分类,一个栏目可以有多个子分类,一个子分类又可以有分裂,例如:新闻栏目下有每日早报和每日晚报两个栏目,其中每日早报下面又分为上海早报,北京早报,杭州早报,下面是京东首页的分类图。
      



      




    数据库设计


    我们在设计数据库的时候仅仅使用一张表就可以把上面的关系给捋清楚,就是通过一个parentid字段,让我们开看一下这张表的表结构


      



    各位看官可以看一下建表语句


      
    1. DROP TABLE IF EXISTS `menu`;
    2. CREATE TABLE `menu`  (
    3.   `id` int(11) NOT NULL AUTO_INCREMENT COMMENT "主键递增",
    4.   `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT "分类名称",
    5.   `parentid` int(11) NULL DEFAULT NULL COMMENT "父节点id",
    6.   `url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT "分类链接",
    7.   `icon` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT "分类图标",
    8.   `order` int(11) NULL DEFAULT NULL COMMENT "分类排序权重",
    9.   PRIMARY KEY (`id`) USING BTREE
    10. ) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
    复制代码

      
    再让我们来插入一点测试数据
      
    1. INSERT INTO `menu` VALUES (1, "新闻", 0, "/www/xinwen", "xxx", 1);
    2. INSERT INTO `menu` VALUES (2, "每日日报", 1, "/www/meiriribao", "xxx", 2);
    3. INSERT INTO `menu` VALUES (3, "每日晚报", 1, "/www/zaobao", "xxx", 1);
    4. INSERT INTO `menu` VALUES (4, "河南日报", 2, "/www/henan", "xxx", 2);
    5. INSERT INTO `menu` VALUES (5, "上海日报", 2, "/www/shanghai", "xxx", 1);
    6. INSERT INTO `menu` VALUES (6, "南京日报", 2, "/www/nanjing", "xxx", 3);
    7. INSERT INTO `menu` VALUES (7, "开封日报", 4, "/www/zhoukou", "xxx", 2);
    8. INSERT INTO `menu` VALUES (8, "郑州日报", 4, "/www/zhenghzou", "xxx", 3);
    复制代码

      

       现在我们来看一下java程序中该如何从数据库中读取数据这样的数据返回页面。在下在项目中用的是SSM框架因为并不是SSM框架教程,这里仅仅贴出Dao层,简单至极
      
      
       
      
    1. List<Menu> findAll();
    复制代码

       
       
       
      
    1. <select id="findAll" resultMap="BaseResultMap">
    2.     select * from menu;
    3.   </select>
    复制代码

       
      
       看一下菜单对应的实体
       
      
       
      
       
       
       
       
    1. package com.sys.domain;
    2. import java.util.List;
    3. public class Menu implements Comparable<Menu> {
    4.     private Integer id;
    5.     private String name;
    6.     private Integer parentid;
    7.     private String url;
    8.     private String icon;
    9.     private Integer order;
    10.     //子菜单列表
    11.     private List<Menu> children;
    12.     public List<Menu> getChildren() {
    13.         return children;
    14.     }
    15.     public void setChildren(List<Menu> children) {
    16.         this.children = children;
    17.     }
    18.     public Integer getId() {
    19.         return id;
    20.     }
    21.     public void setId(Integer id) {
    22.         this.id = id;
    23.     }
    24.     public String getName() {
    25.         return name;
    26.     }
    27.     public void setName(String name) {
    28.         this.name = name == null ? null : name.trim();
    29.     }
    30.     public Integer getParentid() {
    31.         return parentid;
    32.     }
    33.     public void setParentid(Integer parentid) {
    34.         this.parentid = parentid;
    35.     }
    36.     public String getUrl() {
    37.         return url;
    38.     }
    39.     public void setUrl(String url) {
    40.         this.url = url == null ? null : url.trim();
    41.     }
    42.     public String getIcon() {
    43.         return icon;
    44.     }
    45.     public void setIcon(String icon) {
    46.         this.icon = icon == null ? null : icon.trim();
    47.     }
    48.     public Integer getOrder() {
    49.         return order;
    50.     }
    51.     public void setOrder(Integer order) {
    52.         this.order = order;
    53.     }
    54.     @Override
    55.     public int compareTo(Menu o) {
    56.         if (this.order != o.order) {
    57.             return this.order - o.order;
    58.         }
    59.         return 0;
    60.     }
    61. }
    复制代码

       
       View Code
       
       实体关键点1:实体Menu实现了Comparable接口并实现了compareTo方法
      
       
       
       
      这样就可以直接使用Collections.sort()方法进行List排序
      
       
      实体关键点2:实体中新增一个属性List<Menu> children,用于存储返回页面的子节点
      
       
      

       

       


      
    实体较介绍完了,我们就可以直接看代码啦,都加上注释了很简单



      
    1. package com.sys.menutree;
    2. import com.sys.dao.MenuMapper;
    3. import com.sys.domain.Menu;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.stereotype.Controller;
    6. import org.springframework.web.bind.annotation.RequestBody;
    7. import org.springframework.web.bind.annotation.RequestMapping;
    8. import org.springframework.web.bind.annotation.RequestMethod;
    9. import org.springframework.web.bind.annotation.ResponseBody;
    10. import java.util.*;
    11. /**
    12. * @Author:jimisun
    13. * @Description:
    14. * @Date:Created in 18:02 2018/8/8
    15. * @Modified By:
    16. */
    17. @Controller
    18. @RequestMapping("/menu")
    19. public class MenuController {
    20.     @Autowired
    21.     private MenuMapper menuMapper;
    22.     @RequestMapping(value = "/findTree", method = RequestMethod.POST)
    23.     @ResponseBody
    24.     public Map<String, Object> findTree(@RequestBody(required = false) Menu menu) {
    25.         //构建返回数据
    26.         Map<String, Object> data = new HashMap<String, Object>();
    27.         try {
    28.             //查询到的所有菜单
    29.             List<Menu> allMenu = menuMapper.findAll();
    30.             //根节点
    31.             List<Menu> rootMenu = new ArrayList<Menu>();
    32.             //根据传递的参数设置根节点
    33.             if (menu != null && menu.getId() != null) {
    34.                 //父节点为传递的id为根节点
    35.                 for (Menu nav : allMenu) {
    36.                     if (nav.getParentid().equals(menu.getId())) {
    37.                         rootMenu.add(nav);
    38.                     }
    39.                 }
    40.             } else {
    41.                 //父节点是0的,为根节点。
    42.                 for (Menu nav : allMenu) {
    43.                     if (nav.getParentid().equals(0)) {
    44.                         rootMenu.add(nav);
    45.                     }
    46.                 }
    47.             }
    48.             // 根据Menu类的order排序
    49.             Collections.sort(rootMenu);
    50.             //为根菜单设置子菜单,getClild是递归调用的
    51.             for (Menu nav : rootMenu) {
    52.                 //获取根节点下的所有子节点 使用getChild方法
    53.                 List<Menu> childList = getChild(nav.getId(), allMenu);
    54.                 //给根节点设置子节点
    55.                 nav.setChildren(childList);
    56.             }
    57.             data.put("success", "true");
    58.             data.put("list", rootMenu);
    59.             return data;
    60.         } catch (Exception e) {
    61.             data.put("success", "false");
    62.             data.put("list", new ArrayList());
    63.             return data;
    64.         }
    65.     }
    66.     /**
    67.      * 递归设置栏目的子节点
    68.      *
    69.      * @param id      父节点id
    70.      * @param allMenu 节点列表
    71.      * @return
    72.      */
    73.     private List<Menu> getChild(Integer id, List<Menu> allMenu) {
    74.         //子菜单
    75.         List<Menu> childList = new ArrayList<Menu>();
    76.         for (Menu nav : allMenu) {
    77.             // 遍历所有节点,将所有菜单的父id与传过来的根节点的id比较
    78.             //相等说明:为该根节点的子节点。
    79.             if (nav.getParentid().equals(id)) {
    80.                 childList.add(nav);
    81.             }
    82.         }
    83.         //递归设置子节点
    84.         for (Menu nav : childList) {
    85.             nav.setChildren(getChild(nav.getId(), allMenu));
    86.         }
    87.         //排序
    88.         Collections.sort(childList);
    89.         //如果节点下没有子节点,返回一个空List(递归退出)
    90.         if (childList.size() == 0) {
    91.             return new ArrayList<Menu>();
    92.         }
    93.         return childList;
    94.     }
    95. }
    复制代码

      
    View Code

    最后我们来看一下功能演示
    直接发送直接请求接口,获取的是所有分类

    请求结果



      
    1. {
    2.     "success": "true",
    3.     "list": [
    4.         {
    5.             "id": 5,
    6.             "name": "上海日报",
    7.             "parentid": 2,
    8.             "url": "/www/shanghai",
    9.             "icon": "xxx",
    10.             "order": 1,
    11.             "children": []
    12.         },
    13.         {
    14.             "id": 4,
    15.             "name": "河南日报",
    16.             "parentid": 2,
    17.             "url": "/www/henan",
    18.             "icon": "xxx",
    19.             "order": 2,
    20.             "children": [
    21.                 {
    22.                     "id": 7,
    23.                     "name": "开封日报",
    24.                     "parentid": 4,
    25.                     "url": "/www/zhoukou",
    26.                     "icon": "xxx",
    27.                     "order": 2,
    28.                     "children": []
    29.                 },
    30.                 {
    31.                     "id": 8,
    32.                     "name": "郑州日报",
    33.                     "parentid": 4,
    34.                     "url": "/www/zhenghzou",
    35.                     "icon": "xxx",
    36.                     "order": 3,
    37.                     "children": []
    38.                 }
    39.             ]
    40.         },
    41.         {
    42.             "id": 6,
    43.             "name": "南京日报",
    44.             "parentid": 2,
    45.             "url": "/www/nanjing",
    46.             "icon": "xxx",
    47.             "order": 3,
    48.             "children": []
    49.         }
    50.     ]
    51. }
    复制代码

      
    View Code

      
    发送请求接口,并附带要查询的分类id

    结果如下



      
    1. {
    2.     "success": "true",
    3.     "list": [
    4.         {
    5.             "id": 5,
    6.             "name": "上海日报",
    7.             "parentid": 2,
    8.             "url": "/www/shanghai",
    9.             "icon": "xxx",
    10.             "order": 1,
    11.             "children": []
    12.         },
    13.         {
    14.             "id": 4,
    15.             "name": "河南日报",
    16.             "parentid": 2,
    17.             "url": "/www/henan",
    18.             "icon": "xxx",
    19.             "order": 2,
    20.             "children": [
    21.                 {
    22.                     "id": 7,
    23.                     "name": "开封日报",
    24.                     "parentid": 4,
    25.                     "url": "/www/zhoukou",
    26.                     "icon": "xxx",
    27.                     "order": 2,
    28.                     "children": []
    29.                 },
    30.                 {
    31.                     "id": 8,
    32.                     "name": "郑州日报",
    33.                     "parentid": 4,
    34.                     "url": "/www/zhenghzou",
    35.                     "icon": "xxx",
    36.                     "order": 3,
    37.                     "children": []
    38.                 }
    39.             ]
    40.         },
    41.         {
    42.             "id": 6,
    43.             "name": "南京日报",
    44.             "parentid": 2,
    45.             "url": "/www/nanjing",
    46.             "icon": "xxx",
    47.             "order": 3,
    48.             "children": []
    49.         }
    50.     ]
    51. }
    复制代码

      
    View Code

    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-4-26 20:36 , Processed in 0.415593 second(s), 48 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表