递归解决根据父节点遍历权限树菜单的问题--------mysql数据中的树表

本人几乎没写过博客,感觉要学的知识和要做的事情太多,没时间。但发现用博客记录自己学习心得非常好,就抽时间写点,供自己以后参考也分享给某些需要的人,我水平有限,请多指教!

最近在独自尝试开发一个小型的oa系统以巩固下自己对java ssh框架的学习。这里记录下开发中的一些心得体会。

我把系统菜单设计成树,用一张表存储,各个菜单项之间是父子关系,当我们要根据用户权限去数据库中取菜单项时,发现sql语句不好解决。之前在网上查看了一些帖子博文,发现oracle中有对这个需求有专门的sql语句:类似这样

select * from pub_entity a start with a.entity_id = 88 connect by prior a.entity_id = a.super_entity_id;

但我使用的mysql没有,一些文章中说用mysql的存储过程解决,我这个刚出道的菜鸟感觉太复杂了,没去尝试。最后想到可以直接用递归算法解决:

菜单表:

实体类代码:

  1 package com.xuwei.oa.entity;
  2
  3 import java.io.Serializable;
  4 import java.util.Set;
  5
  6 import javax.persistence.Column;
  7 import javax.persistence.Entity;
  8 import javax.persistence.GeneratedValue;
  9 import javax.persistence.GenerationType;
 10 import javax.persistence.Id;
 11 import javax.persistence.ManyToMany;
 12 import javax.persistence.Table;
 13
 14 import org.apache.struts2.json.annotations.JSON;
 15 import org.hibernate.annotations.GenericGenerator;
 16
 17 /**
 18  * 菜单管理实体类
 19  * @author David
 20  *
 21  */
 22 @Entity
 23 @Table(name="t_menu")
 24 public class Menu implements Serializable{
 25     @Id  //设置主键生成策略为手动分配
 26     @GenericGenerator(name="menuGenerator",strategy="assigned")
 27     @GeneratedValue(generator="menuGenerator")
 28     private Long mid;//主键
 29     @Column(name = "name", length = 15)
 30     private String name;//树上的节点的名称
 31     @Column(name = "isParent")
 32     private Boolean isParent;//是否为文件夹节点
 33     @Column(name = "icon", length = 100)
 34     private String icon;//图标图片的路径
 35     @Column(name = "checked", length = 5)
 36     private Boolean checked;
 37     @Column(name = "url", length = 60)
 38     private String url;//单击菜单跳转的action
 39     @Column(name = "target", length = 15)
 40     private String target;//页面显示位置
 41     @Column(name = "pid", length = 5)
 42     private Long pid;//父节点ID
 43
 44     public Long getMid() {
 45         return mid;
 46     }
 47     public void setMid(Long mid) {
 48         this.mid = mid;
 49     }
 50     public Long getPid() {
 51         return pid;
 52     }
 53     public void setPid(Long pid) {
 54         this.pid = pid;
 55     }
 56     public String getName() {
 57         return name;
 58     }
 59     public void setName(String name) {
 60         this.name = name;
 61     }
 62     public Boolean getIsParent() {
 63         return isParent;
 64     }
 65     public void setIsParent(Boolean isParent) {
 66         this.isParent = isParent;
 67     }
 68     public String getIcon() {
 69         return icon;
 70     }
 71     public void setIcon(String icon) {
 72         this.icon = icon;
 73     }
 74     public Boolean getChecked() {
 75         return checked;
 76     }
 77     public void setChecked(Boolean checked) {
 78         this.checked = checked;
 79     }
 80     public String getUrl() {
 81         return url;
 82     }
 83     public void setUrl(String url) {
 84         this.url = url;
 85     }
 86     public String getTarget() {
 87         return target;
 88     }
 89     public void setTarget(String target) {
 90         this.target = target;
 91     }
 92
 93     @ManyToMany(mappedBy = "menus")
 94     private Set<User> users;//角色set集合
 95     @JSON(serialize=false)
 96     public Set<User> getUsers() {
 97         return users;
 98     }
 99     public void setUsers(Set<User> users) {
100         this.users = users;
101     }
102
103
104 }

单元测试代码:

 1     private Session session;
 2     private List<Menu> listMenu=new ArrayList<Menu>();
 3
 4
 5     @Test
 6     public void testQueryAllTreeNodesByRootPid(){
 7         List<Menu> res=new ArrayList<Menu>();
 8         session.beginTransaction();
 9 //        vistTreeNodesByPid(6L);
10         vistTreeNodesByPid(6L,res);
11         for(Menu m:res){
12             System.out.println("*****"+m.getName());
13         }
14         session.getTransaction().commit();
15     }
16
17     public void vistTreeNodesByPid(Long pid,List<Menu> res){
18 //        String hql="from Menu where pid=? order by mid";
19         String hql="from Menu m inner join fetch m.users u where m.pid=? and u.uid=? order by m.mid";
20         Query query=session.createQuery(hql);
21         query.setLong(0, pid);
22         query.setLong(1, 16L);
23         List<Menu> list=query.list();
24         for(Menu m:list){
25             System.out.println(m.getMid()+"--"+m.getName());
26 //            this.listMenu.add(m);
27             res.add(m);
28         }
29         for(Menu m:list){
30             Long tmp_pid=m.getMid();
31             if(tmp_pid!=null){
32                 vistTreeNodesByPid(tmp_pid,res);
33             }
34         }
35     }

这样就轻松解决了这个问题。

时间: 2025-01-02 05:57:50

递归解决根据父节点遍历权限树菜单的问题--------mysql数据中的树表的相关文章

Mysql数据中Packet for query is too large错误的解决方法

有时,程序在连接mysql执行操作数据库时,会出现如下类似错误信息: Packet for query is too large (4230 > 1024). You can change this value on the server by setting the max_allowed_packet' variable. 这个错误的大致原因是:向mysql数据库发送查询命令时,默认性况下,一个包的大小是1024,实际一条语句的长度,就大小这个,所以执行语句报错.解决的方式,就是调整mysq

再谈树---无根树转有根树( dfs搜索转化+fa数组记录父节点) *【模板】

#include <stdio.h> #include <string.h> #include <stdlib.h> #include <vector> #include <algorithm> #define N 100000+2 using namespace std; //无根树转有根树算法 /* 算法分析:所谓无根树,就是根节点任意的树.我们可以给它确定一个根节点. 我们可以假定认为某一个节点为根节点,然后从该节点开始进行dfs或者bfs

Oracle树查询(查询所有子节点,父节点等等)_转载

Oracle树查询(查询所有子节点,父节点等等) 转载 2016年01月14日 10:11:55 Oracle树查询的最重要的就是select...start with... connect by ...prior 语法了.依托于该语法,我们可以将一个表形结构的中以树的顺序列出来.在下面列述了Oracle中树型查询的常用查询方式以及经常使用的与树查询相关的Oracle特性函数等,在这里只涉及到一张表中的树查询方式而不涉及多表中的关联等. 以我做过的一个项目中的表为例,表结构如下: Sql代码 1

LCA-最小公共父节点

有一个普通二叉树,AB分别为两个子节点,求AB最近(深度最大)的公共父节点. 此题仍然是一个老题,有着多种解决方法,本文针对其中三种方法来进行分析总结. 这三种方法分别是:递归法,tarjan离线算法,RMQ在线算法. 递归法 递归法比较直观简单,思路如下: 首先判定当前节点root是否是A节点或者B节点,若是的话直接返回该节点 若不是,分别对root节点的左右子树进行递归查找最小公共父节点,若左右子树都返回了节点,那么表示当前节点就是最小公共父节点,若只有其中一个子树返回了结果,那么就返回该结

[osg]节点遍历nodevisitor浅析

参考:https://www.cnblogs.com/hzhg/archive/2010/12/17/1908764.html OSG中节点的访问使用的是一种访问器模式.一个典型的访问器涉及抽象访问者角色(Visitor), 具体访问者(Concrete Visitor), 节点角色(Node). OSG中访问者角色为NodeVisitor类,其基本结构如下: NodeVisitor(TraversalMode tm) //构造函数,TraversalMode为节点树的遍历方式 //TRAVER

LCA最小公共父节点的解题思路

LCA最小公共父节点解法: 1.二叉搜索树: 中序遍历是升序,前序遍历即按序插入建树的序列. 二叉搜索树建树最好用前序+中序,如果用前序建树,最坏情况会退化为线性表,超时. 最近公共祖先甲级: A1143,1151 利用二叉搜索树的性质寻找结点u和v的最低公共祖先(递归解法) 1)如果根结点的值大于max(u,v),说明u和v均在根结点的左子树,则进入根结点的左子结点继续递归 2)如果根结点的值小于min(u,v),说明u和v均在根结点的右子树,则进入根结点的右子结点继续递归 3)剩下的情况就是

[ 题解 ] [ 最小公共父节点 ] E. Family Tree

http://codeforces.com/group/NVaJtLaLjS/contest/238202/problem/E 题意: 输入数字N,还有两只牛的名字: 输入N行父子关系(题中为母女)即两个名字,前者是父,后者是子: 问两只牛是什么亲属关系. 具体的输出规则(亲属关系)请见原题. 示例: Input: 7 AA BB MOTHER AA GGMOTHER BB MOTHER SISTER GMOTHER MOTHER GMOTHER AUNT AUNT COUSIN GGMOTHE

EasyUI 树菜单

EasyUI 树菜单 通过ssm框架项目实现EasyUI 的树菜单的单选,复选,异步加载树,同步加载树和树权限控制等功能. 本章知识点 效果图: 需求:通过SSM框架,实现EasyUI 树菜单的单选,多选,异步加载,同步加载的功能 技术:Spring,SpringMVC,Mybatis,EasyUI 明说:使用EasyUI-Tree,必须严格遵守它的规则,如异步加载树节点的 id,异步加载树返回值的格式等.如果按照其规则来做,你会发现 EasyUI 很简单.反之到处都是吭! 源码:见文章底部 场

jQuery和CSS3动感手风琴多级列表树菜单

mtree.js是一款效果非常炫酷的jQuery和CSS3动感手风琴多级列表树菜单插件.该手风琴多级列表树菜单基于velocity.js和CSS3 transitions来制作.它提供了5种主题样式的手风琴列表树菜单效果.这5种主题分别为:bubba,skinny,transit,jet,nix. 效果演示:http://www.htmleaf.com/Demo/201505251902.html 下载地址:http://www.htmleaf.com/jQuery/Menu-Navigatio