关于树形权限关系

来源:互联网 发布:四川省教师网络培训 编辑:程序博客网 时间:2024/06/01 07:57

在做传统企业技术解决方案的过程中,经常会遇到将这样一种数据权限关系。

  上级可见下级所有数据,同级之间权限不可见,下级不可见上级数据。并且业务场景经常会出现需要大量部门单位,此时如果部门关系存储在传统数据库中的方案就显得无力支撑。结构简单示例如图:

这里写图片描述

    如果按这种结构,部门总数10万+,每日请求需求在百万到千万级别。部门关系数据改动较少,查询量很多,并且存在大量递归权限查询。为了支持针对此种业务场景,做了个redis的部门权限树,部门数据和权限数据分开存储,部门数据仍然采用关系型数据库mysql,关系数据存储在redis中,关键代码如下

treenode是树形结构的节点,包含两个部分node的上级节点,node的下级节点

public class TreeNode {    //当前node节点的上级    private JSONArray nodeUpperList;    //所有当前node节点的下级    private JSONArray nodeLowerList;    /**     * @return the nodeUpperList     */    public JSONArray getNodeUpperList() {        return nodeUpperList;    }    /**     * @param nodeUpperList the nodeUpperList to set     */    public void setNodeUpperList(JSONArray nodeUpperList) {        this.nodeUpperList = nodeUpperList;    }    /**     * @return the nodeLowerList     */    public JSONArray getNodeLowerList() {        return nodeLowerList;    }    /**     * @param nodeLowerList the nodeLowerList to set     */    public void setNodeLowerList(JSONArray nodeLowerList) {        this.nodeLowerList = nodeLowerList;    }}

定义treenode的新增结构,包含addSynDep添加节点,adjustAddSynDep调整添加后的上级节点。

/**     *  treerole 映射结构添加     * @param parentId:父级ID     * @param nodeId:nodeID     * @return rows =0 fail | >0 sucess     */    public static Long addTreeRole(Long pNodeId, Long nodeId) throws Exception{        // TODO Auto-generated method stub        //返回结果        Long rows = 0l;        TreeNode treeNode = new TreeNode();        JSONArray arrObj = null;        if( nodeId > 0 ){            //部门key            String dRedisKey = nodeId.toString();            //父亲key            String pRedisKey = pNodeId.toString();            //第一层节点并且父节点不存在             if( pNodeId == 0 && !redisBase.hexists(redisKey,pRedisKey) ){                //一级节点上级为空                arrObj = JSONArray.fromObject( "[]" );                treeNode.setNodeUpperList( arrObj );                treeNode.setNodeLowerList( arrObj );                rows = redisBase.hset(redisKey, dRedisKey, SerializeUtil.serialize(treeNode).toString());            }else if( pNodeId > 0 ){                //不是一级节点                //此处保证线程安全 添加节点进入映射结构                arrObj = addSynDep(dRedisKey,pRedisKey,pNodeId);            }            //***************当写入场景过多时  此处需要调整   BY Today            //更新所有上级数据              if( arrObj != null){                @SuppressWarnings("rawtypes")                Iterator iterator = arrObj.iterator();                while( iterator.hasNext() ){                    String ppRedisKey = iterator.next().toString();                    adjustAddSynDep(ppRedisKey,nodeId);                }            }        }        return rows;    }    //线程安全调整    private static synchronized void adjustAddSynDep(String ppRedisKey,Long nodeId){        String ppJsonString = redisBase.hget( redisKey,ppRedisKey );        TreeNode treeNode = (TreeNode) SerializeUtil.unserialize( ppJsonString.getBytes() );        JSONArray ppArrObj0 = treeNode.getNodeLowerList();        //将自己添加到上级的下级中        ppArrObj0.add( nodeId );        treeNode.setNodeLowerList( ppArrObj0 );        redisBase.hset(redisKey, ppRedisKey, SerializeUtil.serialize(treeNode).toString());    }    //线程安全添加    private static synchronized JSONArray addSynDep(String dRedisKey,String pRedisKey,Long parentId){        if( redisBase.hexists(redisKey,dRedisKey)  || !redisBase.hexists(redisKey,pRedisKey) ){            //部门存在 或者 父亲不存在            return null;        }        TreeNode treeNode = new TreeNode();        //取出父亲数据        String jsonString = redisBase.hget( redisKey,pRedisKey );        TreeNode pTreeNode = (TreeNode)SerializeUtil.unserialize(jsonString.getBytes());        //下级为空        JSONArray arrObj0 = JSONArray.fromObject( "[]" );        treeNode.setNodeLowerList( arrObj0 );        // 父亲的上级        JSONArray arrObj1 = pTreeNode.getNodeUpperList();        //追加自己的父亲        arrObj1.add(parentId);        treeNode.setNodeUpperList( arrObj1 );        Long rows = redisBase.hset(redisKey, dRedisKey, SerializeUtil.serialize(treeNode).toString());        if( rows > 0 ){            //成功 返回自己的上级            return arrObj1;        }        //失败        return null;}

全部结构代码可查看https://github.com/zhaoshensky/treerole.git