开发中我们难免会遇到各种树形结构展示的场景。比如用户登录系统后菜单的展示,某些大型购物网站商品的分类展示等等,反正开发中会遇到各种树形展示的功能,这些功能大概处理的思路都是一样的,所以本文就总结一下树形结构的代码生成,在开发的时候套用这种结构就可以了。

好了正文开始,首先相关的SQL脚本【MYSQL】提供给你(包吃包住包SQL)【如果巅峰留不住那就进厂包吃住】。

DDL语句:

  1. CREATE TABLE `student`.`SYS_menu`(
  2. `ID` INT(10) NOT NULL AUTO_INCREMENT,
  3. `name` VARCHAR(200) NOT NULL,
  4. `permissions` VARCHAR(1000),
  5. `url` VARCHAR(200),
  6. `description` VARCHAR(2000),
  7. `icon_cls` VARCHAR(2000),
  8. `pid` INT(10),
  9. `status` INT(2),
  10. `resource_type` INT(2),
  11. `sort` INT(6),
  12. `create_time` TIMESTAMP,
  13. `update_time` TIMESTAMP,
  14. PRIMARY KEY (`ID`)
  15. ) ENGINE=INNODB CHARSET=utf8;

初始化语句:

  1. INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT)
  2.  
  3. VALUES('主菜单',NULL,NULL,'数据主菜单',NULL,0,1,1,NOW(),NOW(),NULL) ;
  4.  
  5. INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT)
  6.  
  7. VALUES('菜单1',NULL,NULL,'菜单1',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='主菜单') a ),1,1,NOW(),NOW(),1) ;
  8.  
  9. INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT)
  10.  
  11. VALUES('菜单2',NULL,NULL,'菜单2',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='主菜单') a ),1,1,NOW(),NOW(),2) ;
  12.  
  13. INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT)
  14.  
  15. VALUES('菜单3',NULL,NULL,'菜单3',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='主菜单') a ),1,1,NOW(),NOW(),3) ;
  16.  
  17. INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT)
  18.  
  19. VALUES('菜单1.1',NULL,NULL,'菜单1的子菜单',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜单1') a ),1,1,NOW(),NOW(),1) ;
  20.  
  21. INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT)
  22.  
  23. VALUES('菜单1.2',NULL,NULL,'菜单1的子菜单',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜单1') a ),1,1,NOW(),NOW(),2) ;
  24.  
  25. INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT)
  26.  
  27. VALUES('菜单1.3',NULL,NULL,'菜单1的子菜单',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜单1') a ),1,1,NOW(),NOW(),3) ;
  28.  
  29. INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT)
  30.  
  31. VALUES('菜单2.1',NULL,NULL,'菜单2的子菜单',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜单2') a ),1,1,NOW(),NOW(),1) ;
  32.  
  33. INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT)
  34.  
  35. VALUES('菜单2.2',NULL,NULL,'菜单2的子菜单',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜单2') a ),1,1,NOW(),NOW(),2) ;
  36.  
  37. INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT)
  38.  
  39. VALUES('菜单2.3',NULL,NULL,'菜单2的子菜单',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜单2') a ),1,1,NOW(),NOW(),3) ;
  40.  
  41. INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT)
  42.  
  43. VALUES('菜单3.1',NULL,NULL,'菜单3的子菜单',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜单3') a ),1,1,NOW(),NOW(),1) ;
  44.  
  45. INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT)
  46.  
  47. VALUES('菜单3.2',NULL,NULL,'菜单3的子菜单',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜单3') a ),1,1,NOW(),NOW(),2) ;
  48.  
  49. INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT)
  50.  
  51. VALUES('菜单3.3',NULL,NULL,'菜单3的子菜单',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜单3') a ),1,1,NOW(),NOW(),3)

数据结构一般就是上面得那样,只是初始化得数据按照你开发得需求初始化。

然后就是创建简单得项目,好了那我就贴出相关得代码,这些大家开发得时候可以根据需求进行嵌套使用。

  1. // entity
  2. @Data
  3. @TableName("sys_menu")
  4. public class SysMenu implements Serializable {
  5. private static final long serialVersionUID = 1L;
  6. @TableId
  7. private Integer id;
  8. private String name;
  9. private String permissions;
  10. private String url;
  11. private String description;
  12. private String iconCls;
  13. private Integer pid;
  14. private Integer status;
  15. private Integer resourceType;
  16. private Integer sort;
  17. private Date createTime;
  18. private Date updateTime;
  19. /**
  20. * 此处为了简单我就不新建DTO对象了,
  21. * 加一个children属性,注意如果不是数据库的字段一定要
  22. * 加下面d额那个注解
  23. */
  24. @TableField(exist=false)
  25. private List<SysMenu> children;
  26.  
  27. }
  1. // mapper接口,很简单没有多余代码
  2. public interface SysMenuDao extends BaseMapper<SysMenu> {
  3.  
  4. }
  1. // mapper 文件也是没有多余的代码,使用Mybatis-Plus特有的就行
  2. // 其中下面的resultMap也可以去掉。
  3. <mapper namespace="io.renren.mapper.SysMenuDao">
  4. <!-- 可根据自己的需求,是否要使用 -->
  5. <resultMap type="io.renren.domain.SysMenu" id="sysMenuMap">
  6. <result property="id" column="ID"/>
  7. <result property="name" column="name"/>
  8. <result property="permissions" column="permissions"/>
  9. <result property="url" column="url"/>
  10. <result property="description" column="description"/>
  11. <result property="iconCls" column="icon_cls"/>
  12. <result property="pid" column="pid"/>
  13. <result property="status" column="status"/>
  14. <result property="resourceType" column="resource_type"/>
  15. <result property="sort" column="sort"/>
  16. <result property="createTime" column="create_time"/>
  17. <result property="updateTime" column="update_time"/>
  18. </resultMap>
  19. </mapper>
  1. // service 主要的逻辑代码就在这里。
  2. public interface SysMenuService extends IService<SysMenu> {
  3.  
  4. List<SysMenu> getMenuTree();
  5. }
  6.  
  7. @Service("sysMenuService")
  8. public class SysMenuServiceImpl extends ServiceImpl<SysMenuDao, SysMenu> implements SysMenuService {
  9.  
  10. @Autowired
  11. private SysMenuDao sysMenuDao ;
  12. @Override
  13. public List<SysMenu> getMenuTree() {
  14. //查询出所有菜单
  15. List<SysMenu> sysMenus = sysMenuDao.selectList(null);
  16. //2、组装成树形结构
  17. //2.1)、找到所有的一级菜单
  18. List<SysMenu> level1Menus = sysMenus.stream().filter(sysMenu ->
  19. sysMenu.getPid() == 0
  20. ).map((menu) -> {
  21. menu.setChildren(getChildrens(menu, sysMenus));
  22. return menu;
  23. // 排序
  24. }).sorted((menu1, menu2) -> {
  25. return (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort());
  26. }).collect(Collectors.toList());
  27. return level1Menus;
  28. }
  29.  
  30. //递归查找所有菜单的子菜单,主要就是用了这个递归查询。
  31. // 我也都写了相关的注释。
  32. private List<SysMenu> getChildrens(SysMenu root, List<SysMenu> all) {
  33.  
  34. List<SysMenu> children = all.stream().filter(sysMenu -> {
  35. return sysMenu.getPid() == root.getId();
  36. }).map(sysMenu -> {
  37. //1、找到子菜单
  38. sysMenu.setChildren(getChildrens(sysMenu, all));
  39. return sysMenu;
  40. }).sorted((menu1, menu2) -> {
  41. //2、菜单的排序
  42. return (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort());
  43. }).collect(Collectors.toList());
  44. return children;
  45. }

有的小伙伴可能会说,博主我们项目使用的jdk7 。上面的代码使用不了啊,这篇文章对我来说不合适啊。好了安排上,既然写文章我就要写的明明白白,下面是不使用Stream流完成的功能。

  1. List<SysMenu> getMenuTreeVerLowJava8() ;
  2.  
  3. @Override
  4. public List<SysMenu> getMenuTreeVerLowJava8() {
  5. List<SysMenu> sysMenus = sysMenuDao.selectList(null);
  6. List<SysMenu> tree = new ArrayList<>();
  7. for (SysMenu sysmenu: sysMenus) {
  8. if (sysmenu.getPid()==0){
  9. tree.add(getChildrens02(sysmenu,sysMenus)) ;
  10. }
  11. }
  12. return tree;
  13. }
  14.  
  15. /**
  16. * 不使用stream的递归调用
  17. * @param list
  18. * @return
  19. */
  20. private SysMenu getChildrens02(SysMenu sysMenu, List<SysMenu> list) {
  21.  
  22. List<SysMenu> children = new ArrayList<SysMenu>();
  23. for (SysMenu sysMenu2 : list) {
  24. if (sysMenu2.getPid() == sysMenu.getId()) {
  25. // 递归调用
  26. SysMenu result = getChildrens02(sysMenu2, list);
  27. children.add(result);
  28. }
  29. }
  30. sysMenu.setChildren(children);
  31. return sysMenu;
  32. }

使用Java7的菜单树我没有进行排序,Java7的排序使用起来也很简单,相信大家开发的时候都使用过,大家可以自行完成排序。生成的树形结构太多我就不贴出来了肯定是正确的。

开发中就是需要这种记录,为什么呢,当你没看到这篇文章你写一个树形结构的代码可能需要一天,而你点一下关注,后面开发中你遇到这种功能的开发一个小时应该就能搞定并且还没有问题,极大的提高了开发效率,领导看到你效率那么高应该也会很高兴,说不定升职加薪就在眼前。点点关注何乐而不为呢?生活中也一样,你同样需要记录总结,这样你应该也越走越顺,比如你今天上班路上遇到一个坑,你记住了。下次走过这里你就会避开这个坑,路也越走越顺了。

11

使用Mybatis生成树形菜单-适用于各种树形场景的更多相关文章

  1. 雷林鹏分享:jQuery EasyUI 树形菜单 - 创建异步树形菜单

    jQuery EasyUI 树形菜单 - 创建异步树形菜单 为了创建异步的树形菜单(Tree),每一个树节点必须要有一个 'id' 属性,这个将提交回服务器去检索子节点数据. 创建树形菜单(Tree) ...

  2. 雷林鹏分享:jQuery EasyUI 树形菜单 - 创建复杂树形网格

    jQuery EasyUI 树形菜单 - 创建复杂树形网格 树形网格(TreeGrid)可以展示有限空间上带有多列和复杂数据电子表格.本教程将演示如何将表格数据排列在分割的网格和多行表头中,以便组织共 ...

  3. 雷林鹏分享:jQuery EasyUI 树形菜单 - 创建基础树形网格

    jQuery EasyUI 树形菜单 - 创建基础树形网格 树形网格(TreeGrid)组件从数据网格(DataGrid)继承,但是允许在行之间存在父/子节点关系.许多属性继承至数据网格(DataGr ...

  4. JQuery实现动态生成树形菜单

    jQuery实现动态生成树形菜单 有一个需求:菜单导航条需要依据不同的权限动态提取出来.计划是将功能模块与用户权限之间的关系保持到一个配置表中.所以功能菜单的话就需要动态提取出来再显示.借助jquer ...

  5. JavaScript生成树形菜单(递归算法)

    1.最终效果图(这里仅为实现算法,并加载至页面,不做任何css界面优化) 注释:本示例包含三级目录菜单,但实际上可支持N级(可使用该代码自行测试) 2.数据源 菜单信息一般来源于数据库中数据表,且为自 ...

  6. WEB开发中前后台树形菜单的展示设计

    在WEB开发中经常需要进行树形菜单的展示,本例通过不同角度的总结了如下三种实现方式: 通过JS的递归实现前端菜单DOM的动态创建 通过JSP的include指令结合JSTL表达式语言递归实现菜单的展示 ...

  7. jquery树形菜单完整代码

    本实例实现了树形的动态菜单,兼容IE8,火狐,Chrome等浏览器.使用了jQuery的toggle() 方法.效果和代码如下: <!DOCTYPE html PUBLIC "-//W ...

  8. 实用的树形菜单控件tree

     jQuery plugin: Treeview  这个插件能够把无序列表转换成可展开与收缩的Tree. jQuery plugin: Treeview  jQuery  jstree  jsTree ...

  9. Android 多级树形菜单

    在Android里要实现树形菜单,都是用ExpandableList(也有高手自己继承ListView或者LinearLayout来做),但是ExpandableList一般只能实现2级树形菜单... ...

  10. html树形菜单控件

    html树形菜单控件  链接 http://www.ithao123.cn/content-713974.html         jQuery plugin: Treeview  这个插件能够把无序 ...

随机推荐

  1. Ubuntu桌面顶端没有网络图标

    1 问题描述 刚装完新的linux系统后发现桌面顶部没有出现网络连接图标,网络无法进行连接配置. 2 解决方案 打开终端执行命令 nmcli network on或者sudo nmcli networ ...

  2. PHP微信三方平台-授权登录

    一.逻辑步骤解析 步骤 1:第三方平台方获取预授权码(pre_auth_code) 步骤 2:引入用户进入授权页 第三方平台方可以在自己的网站中放置"微信公众号授权"或者" ...

  3. 【深入浅出 Yarn 架构与实现】5-3 Yarn 调度器资源抢占模型

    本篇将对 Yarn 调度器中的资源抢占方式进行探究.分析当集群资源不足时,占用量资源少的队列,是如何从其他队列中抢夺资源的.我们将深入源码,一步步分析抢夺资源的具体逻辑. 一.简介 在资源调度器中,以 ...

  4. Lodash中常用函数,不建议经常使用,容易让人变懒忘了原生函数

    1.N次循环 <script type="text/javascript"> console.log('------- javascript -------'); // ...

  5. offsetX与offsetLeft

    offsetX:鼠标指针距离当前绑定元素左侧距离,他并不是相对于带有定位的父盒子的x,y坐标, 记住了,很多博客都解释错了 offsetLeft,offsetTop 相对于最近的祖先定位元素.

  6. python语法的入门

    1.变量 1.1: 底层原理:现在内存空间申请一块地址来储存变量值, 然后把申请的内存地址跟变量名绑定在一起 之后只需通过访问变量名就可以获取变量值 1.2:一个变量名只能指向一个内存地址,但是一个内 ...

  7. 前后端分离 nginx 的配置

    前端 nginx # 添加头部信息 proxy_send_timeout 30; # 后端服务器连接超时时间 proxy_read_timeout 30; # 后端服务器数据回传时间 proxy_co ...

  8. express获取登录服务器的IP地址

    let ip = (req.headers['x-real-ip'] || req.connection.remoteAddress).slice(7);      

  9. CentOS7---部署Tomcat和安装Jpress

    总览需求 1. 简述静态网页和动态网页的区别. 2. 简述 Webl.0 和 Web2.0 的区别. 3. 安装tomcat8,配置服务启动脚本,部署jpress应用. 1.简述静态网页和动态网页的区 ...

  10. 解决CKEditor中img标签自动添加style样式的问题-禁止自动设置width和height 帝国cms编辑器图片自动加宽高

    在使用CKEditor的过程中发现,每次上传或添加图片的时候,总会自动给img标签添加width和height的style内联样式.由于网站本身对图片有进行自适应处理(添加了自适应的CSS),所以im ...