论坛首页 Java企业应用论坛

树形菜单的权限控制是个蛋疼的问题【讨论】

浏览 16153 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-10-16   最后修改:2011-10-16

想必,做树权限应该是经常碰到的头痛问题,寻求最佳实现!!



前提是这样的:

现有一已经实现的树形导航,每个节点(包括子节点父节点)都对应了一个页面(如有需要父节点可以设计为不对应页面),树形结构以节点为描述存入数据库,一条节点数据库描述如下:

节点{节点id,父节点id,是否有子节点,子节点个数,其它}

从节点描述可以看出每个节点只知道它的父节点是谁,知道自己有没有子节点,并不知道它的爷爷和儿子具体是谁(当然我们可以用父节点id作为查询条件从而得知“父节点”的子节点有哪些)。

前台js已实现根据节点数据自动通过父子关系组装显示整个树。


需求:

(1)现在要对这棵树做权限控制,实现不同的人看到不同的树型导航,也就是如果用户对某个节点没有权限那么次节点对此用户不显示(这里的不显示是指后台没有读出此节点的数据库数据给前台,而不是前台通过js隐藏)

(2)树节点比较多,不宜过多操作数据库。

(3)权限系统希望独立出去,也就是不能在节点数据库表结构上添加其它列

(4)权限系统可以建立自己的数据库表

(5)权限系统可以读取节点信息表和用户表(用户表归权限系统)但是不能修改其信息

(6)全线系统要达到:能给用户配置指定节点的权限(暂定只有访问权限)

可以任意发挥!可以任意添加表!可以任意添加逻辑!只要不改变节点表。


大体思路:

登录部分:
用户登录系统 -> 将用户名、密码发送到权限系统 -> 权限系统返回是否允许登录

树生成部分:
系统将用户名发到权限系统 -> 权限系统返回其可访问的节点信息【1】 -> 系统根据节点信息组装树【2】

问题来了:
(1)建立什么样的权限系统表结构(包括用户表)来映射用户和树节点表最好?
(2)在【1】处用什么样的算法达到迅速读取某用户对应的节点信息?
(3)在【2】处要组装完整的树光有子节点是不行的,还必须查处它的父节点和爷爷节点直到树根,不然树是断开的无法组装树。



其实如果能写出一个这样的sql就能解决了,这个sql能查出某个用户有权的树节点,并能根据这些节点查出其父节点,再根据父节点查出爷爷节点。。。直到树根。但是这样的查询速度会不会很慢?有什么更好的方法么?


想必做树权限应该是经常碰到的头痛问题,寻求最佳实现,欢迎大家讨论!




   发表时间:2011-10-16   最后修改:2011-10-16
这种事情我在java、c#上实现若干次了。

提示:不要在sql上打主意了,想一次查出来不现实的。

肯定是先顺序全读出到内存(HashMap),再在Java里进行处理。只要子节点中有父节点的ID就可以。

权限和菜单叶子节点就是一张普通的2个字段的关联表就可以了。
0 请登录后投票
   发表时间:2011-10-17  
鱼言风语 写道
这种事情我在java、c#上实现若干次了。

提示:不要在sql上打主意了,想一次查出来不现实的。

肯定是先顺序全读出到内存(HashMap),再在Java里进行处理。只要子节点中有父节点的ID就可以。

权限和菜单叶子节点就是一张普通的2个字段的关联表就可以了。



这。。我都是打的SQL的主意,Oracle时用的Oracle的树状查询语句, 后来发现个好东东 CSDN的MZtree  只要把用户拥有权限查看的 节点查出来 全部显示就完了其在js的结构类似这样
[父节点ID_节点id] xxxxxxxxx
[父节点ID_节点id] xxxxxxxxx
[父节点ID_节点id] xxxxxxxxx

就OK了。表示毫无压力

权限就是节点对应 URL 可以选择是功能节点还是目录节点,功能节点对应url,目录节点嘛就没有对应URL点击无反应,然后可以和用户关联,可以和角色关联。用户的最终权限就是 与其关联的节点与与其角色关联的节点及其当前赋权节点全部的父节点及子节点
0 请登录后投票
   发表时间:2011-10-17  
handong890 写道
鱼言风语 写道
这种事情我在java、c#上实现若干次了。

提示:不要在sql上打主意了,想一次查出来不现实的。

肯定是先顺序全读出到内存(HashMap),再在Java里进行处理。只要子节点中有父节点的ID就可以。

权限和菜单叶子节点就是一张普通的2个字段的关联表就可以了。



这。。我都是打的SQL的主意,Oracle时用的Oracle的树状查询语句, 后来发现个好东东 CSDN的MZtree  只要把用户拥有权限查看的 节点查出来 全部显示就完了其在js的结构类似这样
[父节点ID_节点id] xxxxxxxxx
[父节点ID_节点id] xxxxxxxxx
[父节点ID_节点id] xxxxxxxxx

就OK了。表示毫无压力

权限就是节点对应 URL 可以选择是功能节点还是目录节点,功能节点对应url,目录节点嘛就没有对应URL点击无反应,然后可以和用户关联,可以和角色关联。用户的最终权限就是 与其关联的节点与与其角色关联的节点及其当前赋权节点全部的父节点及子节点



没必要了,要么依赖于特定的数据库实现,或者要写复杂的sql

拿到java/js里处理方便很多
0 请登录后投票
   发表时间:2011-10-17  
一次读出这个人所有的访问权限List
然后在java中进行组装成tree结果,保存 缓存。

然后显示出来
0 请登录后投票
   发表时间:2011-10-17   最后修改:2011-10-17
我之前也做过一点树型菜单的维护,先是完整的读取一棵树,每次更新只读取树中被选中的数据,在树中用"勾"做出标记,同时在页面有一个区域来显示树中的选中数据的情况,同时显示会随着用户修改树中选中元素的情况来更新显示区域
0 请登录后投票
   发表时间:2011-10-17  
菜单树保存为内存树模型,权限信息存为2个线程安全的map结构映射用户与菜单节点权限,每次显示菜单时在内存深度或者广度遍历菜单树,有权限则显示节点,无权限则不显示节点,当然只要任一子节点能显示父节点是应该显示的.我原来是直接返回权限范围内的菜单树的json格式字符串的,那样只用加载一次,如果每次点击再加载更简单.可以封装为通用的树形结构处理代码.
	/**
	 * 树型数据深度遍历
	 * @param child 树节点
	 * @return boolean 
	 */
	private boolean isIterator(TreeNode child) {
		for (Iterator<TreeNode> itsub = new DepthIterator(root.iterator()); itsub.hasNext();) {
			TreeNode childone = itsub.next();
			if (childone == null)
				return Boolean.FALSE;
			if (child.getParentId().equals(childone.getId())) {
				keyMap.put(child.getId(), null);
				childone.addNode(child);
				return Boolean.TRUE;
			}
		}
		return Boolean.FALSE;
	}

深度遍历代码

import java.util.Iterator;

/**
 * <p>
 * 普通树的深度遍历方法
 * </p>
 * 
 * @author kinjoYang
 * @version 1.0 2011-03-06
 * @since 1.0
 * @see java.util.Iterator
 */
public class DepthIterator implements Iterator<TreeNode> {

	/** 迭代器栈 */
	private RzStack<Iterator<TreeNode>> stack = new RzStack<Iterator<TreeNode>>();

	public DepthIterator(Iterator<TreeNode> it) {
		stack.push(it);
	}

	public DepthIterator() {
	}

	/** 是否存在下个元素,没有则返回下级元素的迭代器遍历 */
	public boolean hasNext() {
		if (stack.isEmpty()) {
			return Boolean.FALSE;
		} else {
			Iterator<TreeNode> it = stack.peek();
			if (it.hasNext()) {
				return Boolean.TRUE;
			} else {
				stack.pop();
				return hasNext();
			}
		}
	}

	/** 返回下个元素,无则返回<tt>null</tt> */
	public TreeNode next() {
		if (hasNext()) {
			Iterator<TreeNode> it = stack.peek();
			TreeNode next = it.next();
			if (next.getSize() > 0) {
				stack.push(next.iterator());
			}
			return next;
		} else {
			return null;
		}
	}

	/** 不提供删除方法 */
	public void remove() {
		throw new UnsupportedOperationException("Can't remove node :Kinjo");
	}

}

0 请登录后投票
   发表时间:2011-10-17  

//大概应该是这样,当每个节点展开时,
List<TreeNode> getTreeNode(){
   Collection<Authrition> currentAuths = getCurrentAuths();
   String sql = "from TreeNode t where t.permission in (:perms)";
   Query q = ..;
   q.setParameterList("perms",currentAuths );
   return q.list():
}


Is this good!!!
0 请登录后投票
   发表时间:2011-10-17  
handong890 写道
鱼言风语 写道
这种事情我在java、c#上实现若干次了。

提示:不要在sql上打主意了,想一次查出来不现实的。

肯定是先顺序全读出到内存(HashMap),再在Java里进行处理。只要子节点中有父节点的ID就可以。

权限和菜单叶子节点就是一张普通的2个字段的关联表就可以了。



这。。我都是打的SQL的主意,Oracle时用的Oracle的树状查询语句, 后来发现个好东东 CSDN的MZtree  只要把用户拥有权限查看的 节点查出来 全部显示就完了其在js的结构类似这样
[父节点ID_节点id] xxxxxxxxx
[父节点ID_节点id] xxxxxxxxx
[父节点ID_节点id] xxxxxxxxx

就OK了。表示毫无压力

权限就是节点对应 URL 可以选择是功能节点还是目录节点,功能节点对应url,目录节点嘛就没有对应URL点击无反应,然后可以和用户关联,可以和角色关联。用户的最终权限就是 与其关联的节点与与其角色关联的节点及其当前赋权节点全部的父节点及子节点


关键就是你说的“只要把用户拥有权限查看的 节点查出来”怎么查?
0 请登录后投票
   发表时间:2011-10-17  
wad12302 写道
一次读出这个人所有的访问权限List
然后在java中进行组装成tree结果,保存 缓存。

然后显示出来


“一次读出这个人所有的访问权限”写sql读么?问题就在这啊,用什么样的方法能把这个人所有权限节点查出来?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics