zoukankan      html  css  js  c++  java
  • 【权限的思考】(一)使用反射实现动态权限

      每一个业务系统都会根据业务需要配置各种各样的权限,实现方式也是千差万别,各有各的优缺点。今天我们

    利用反射来做一个小的权限管理Demo。也可以说是插件化的权限管理,通用的插件化框架是实现一个接口或者协定,

    我们的做法是先展示指定的数据,再去动态的加载需要用到的dll和功能。

      大致的思路是这样的,我们从服务或者从数据库里读取哪些dll需要加载,相应的dll下哪些页面可以调用。把这些内容

    动态的添加到页面上,当点击页面上的元素时利用反射,匹配目录下的dll和dll内的页面,进行读取,并显示进行交互,

    从面实现插件化动态加载内容。如下图所示:

         例:

    》.首先我们先建一个工程ReflectionPermissionDemo

          再添加3个类库ReflectionPermissionDemo.A;ReflectionPermissionDemo.B;ReflectionPermissionDemo.C;

    需要注意的是不要在ReflectionPermissionDemo引用后边新建好的3个类库。我们的目标是用反射去加载这些dll库,

    而不是使用引用方式。

    创建完后还需要修改他们的输出路径属性

    ReflectionPermissionDemo就生成到bin目录下

    其它ReflectionPermissionDemo.A;ReflectionPermissionDemo.B;ReflectionPermissionDemo.C三个都指向这个

    目录下生成。这样的目的是让所有的dll都在同一个文件夹下。

    》.创建一些页面

      ReflectionPermissionDemo项目里修改一下页面。在顶部添加一个Panel用来动态添加按钮,这些动态添加上的按钮就是我们利

    用反射动态加载的dll库。在下边也添加一个Panel用于动态显示权限信息,对应是dll库里面有权限的页面。设置他们的

    性Dock一个为Top下边的为Fill。并给他们命名上边的panelTop。叫下边的叫panelBody

      在ReflectionPermissionDemo.A;ReflectionPermissionDemo.B;ReflectionPermissionDemo.C各自创建一些页面,这些页面也

    需要权限设置的允许才能打开。

      在每个页面上放一个标识,标明这个窗体与其它的窗体不同,可以根据个人需要,我这里放的是label写了一些文字标明每个窗体是

    哪个项目的哪个窗体,如下图:

          

     》模拟权限数据

      写一个单例类,创建一些权限数据,用于模拟从服务器上返回的数据。返回的数据有模块id,模块名称,命名空间和父id。

    我们可以把这些数结构想像成一棵树结构。

     /// <summary>
        /// 模拟远程服务器
        /// 返回拥有的权限
        /// </summary>
        public class RemoteService
        {
            public static readonly RemoteService PermissionService = new RemoteService();
            public DataTable PermissionTable { get; private set; }
    
            #region   字段名称
            public readonly string ModuleId = @"ModuleID";
            public readonly string ModuleName = @"ModuleName";
            public readonly string PermissioniNameSpace = @"PermissioniNameSpace";
            public readonly string ParentId = @"ParentID";
            #endregion
    
            private RemoteService()
            {
                AllPermision();
            }
    
            /// <summary>
            /// 所有的权限
            /// </summary>
            /// <returns></returns>
            private DataTable AllPermision()
            {
                PermissionTable = new DataTable();
                #region Permission Page
                PermissionTable.Columns.AddRange(new[]
                {                
                    new DataColumn(ModuleId, typeof (Int32)),               // 模块id
                    new DataColumn(ModuleName, typeof (string)),            // 模块名称                                 
                    new DataColumn(PermissioniNameSpace, typeof (string)),  // 命名空间
                    new DataColumn(ParentId, typeof (Int32))                // 父id          
                });
                #endregion
    
                #region A
    
                CreateNewRow(1001, @"A模块", @"A", -1);
                CreateNewRow(1002, @"A 页面1", @"A.AForm1", 1001);
                // 测试权限先注掉
                //CreateNewRow(1003, @"A 页面2", @"A.AForm2", 1001);
                #endregion
    
    
                #region B 由于我们的例子只不需要B的权限,这里先注掉
                //CreateNewRow(2001, @"B模块", @"B", -1);
                //CreateNewRow(2002, @"B 页面1", @"B.BForm1", 2001);
    
                #endregion
    
                #region C
                CreateNewRow(3001, @"C模块", @"C", -1);
                CreateNewRow(3002, @"C Page1", @"C.CForm1", 3001);
                CreateNewRow(3003, @"C Page2", @"C.CForm2", 3001);
                #endregion
    
                return null;
            }
    
            /// <summary>
            /// 添加行
            /// </summary>
            /// <param name="moduleId"></param>
            /// <param name="moduleName"></param>
            /// <param name="perNameSpace"></param>
            /// <param name="parentId"></param>
            private void CreateNewRow(int moduleId, string moduleName, string perNameSpace, int parentId)
            {
                var newRow = PermissionTable.NewRow();            
                newRow[ModuleId] = moduleId;
                newRow[ModuleName] = moduleName;
                newRow[PermissioniNameSpace] = perNameSpace;
                newRow[ParentId] = parentId;
                PermissionTable.Rows.Add(newRow);
            }
    
           
        }

    》根据权限动态加载页面和利用反射去打开相应的页面

     先整理一下思路。

    1.读取模拟的权限数据。

    2.根据权限数据组织页面元素

      》有哪些dll可以被加载

      》相应的dll内有哪些页面可以被调用

    3.点击页面元素根据保存的数据利用反射把页面展示出来。

    ——————————————————

     >先添加一些字段。

            // 权限数据
            readonly DataTable _permissionDt = RemoteService.PermissionService.PermissionTable;
            // 可用权限动态生成的panel页面
            readonly Dictionary<int, FlowLayoutPanel> _pagePanels = new Dictionary<int, FlowLayoutPanel>();
            // 已加载过的页面
            private readonly Dictionary<string, Type> _formTypes = new Dictionary<string, Type>();

    >根据权限数据动态组织页面

            private void Main_Load(object sender, EventArgs e)
            {            
                var query = _permissionDt.Rows.Cast<DataRow>();
                var parentData = query.Where(x => int.Parse(x[RemoteService.PermissionService.ParentId].ToString()) == -1);
                SettingDllButtons(parentData);
    
            }
    
            /// <summary>
            /// 展示 dll的权限按钮
            /// </summary>
            /// <param name="dt"></param>
            private void SettingDllButtons(IEnumerable<DataRow> drs)
            {
                int width = 80, height = 30, x = 0, y = 0;
                foreach (var dataRow in drs)
                {
                    var btn = new Button
                    {
                        Text = dataRow[RemoteService.PermissionService.ModuleName].ToString(),
                        Size = new Size(width, height),
                        Location = new Point(x, y)        
                    };
                    var index = SettingPageButtons(dataRow);
                    btn.Tag = index;
                    btn.Click += btnDLL_Click;
                    panelTop.Controls.Add(btn);
                    x += width + 10;
                }            
            }
            /// <summary>
            /// 根据 datarow的父id去找到所有的子节点
            /// 加载到相应的页面上组织成按钮
            /// </summary>
            /// <param name="dr"></param>
            /// <returns></returns>
            private int SettingPageButtons(DataRow dr)
            {
                            
                var index = _pagePanels.Count();
    
                var panel = new FlowLayoutPanel
                {
                    Dock = DockStyle.Fill,
                    Location = new Point(0, 0),
                    Visible = false
                };
                panelBody.Controls.Add(panel); 
                _pagePanels[index] = panel;
    
                #region Btns
                var query = _permissionDt.Rows.Cast<DataRow>();
                var data =
                    query.Where(
                        x =>
                            int.Parse(x[RemoteService.PermissionService.ParentId].ToString()) ==
                            int.Parse(dr[RemoteService.PermissionService.ModuleId].ToString()));
                if (!data.Any())
                    return index;
    
                int width = 80, height = 30;
                foreach (var dataRow in data)
                {
                    var btn = new Button
                    {
                        Text = dataRow[RemoteService.PermissionService.ModuleName].ToString(),
                        Size = new Size(width, height),
                        Tag = dataRow[RemoteService.PermissionService.PermissioniNameSpace]
                    };
                    btn.Click += btnPage_Click;             
                    panel.Controls.Add(btn);                
                }
                #endregion
                return index;
            }   

    > 利用点击不同的元素展示相应的页面

            /// <summary>
            /// 显示相应的页面元素
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnDLL_Click(object sender, EventArgs e)
            {
                var index = int.Parse(((Button) sender).Tag.ToString());
                foreach (KeyValuePair<int, FlowLayoutPanel> flowLayoutPanel in _pagePanels)
                {
                    flowLayoutPanel.Value.Visible = flowLayoutPanel.Key == index;                
                }
            }
    
            /// <summary>
            /// 打开相应的page
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnPage_Click(object sender, EventArgs e)
            {
                var name = ((Button) sender).Tag.ToString();
                var form = GetModule(name) as Form;
                form.ShowDialog();
            }
    
            #region
            /// <summary>
            /// 利用反射去加载相应的页面
            /// </summary>
            /// <param name="path"></param>
            /// <param name="mainNamespace"></param>
            /// <returns></returns>
            private object GetModule(string path, string mainNamespace = "ReflectionPermissionDemo")
            {
                var curNamespace = "";
    
                var index = path.IndexOf('.');
                if (index > -1)
                {
                    curNamespace = "." + path.Substring(0, index);
                }
                else
                {
                    curNamespace = "";
                }
    
                var assemblyPath = mainNamespace + curNamespace;
                var classPath = mainNamespace + "." + path;
                object module = null;
                if (_formTypes.ContainsKey(classPath))
                {
                    module = Activator.CreateInstance(_formTypes[classPath]);
                }
                else
                {
                    try
                    {
                        module = Assembly.Load(assemblyPath).CreateInstance(classPath);
                        if (module != null)
                            _formTypes.Add(classPath, module.GetType());
                    }
                    catch
                    {
                        // 查找当前已加载的dll。
                        Type type = null;
                        foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
                        {
                            if (!assembly.FullName.Contains(mainNamespace))
                                continue;
    
                            type = assembly.GetType(classPath, false);
                            if (type != null)
                            {
                                break;
                            }
                        }
                        if (type == null)
                        {
                            throw;
                        }
                        else
                        {
                            module = Activator.CreateInstance(type);
                            if (module != null)
                            {
                                _formTypes.Add(classPath, type);
                            }
                            ;
                        }                  
                    }
                }
                return module;
            }
            #endregion

    跑一下,看一下效果

     源码 : ReflectionPermissionDemo.zip

    github 地址: https://github.com/lpxxn/ReflectionPermissionDemo

  • 相关阅读:
    [转]ASP.NET生成HTML初级解决方案
    HTTPContentTypes 大全
    CSS美化 input type=”file” 兼容所有浏览器
    页面前端的水有多深?再议页面开发(转)
    jQuery对select、checkbox、radio操作小结
    jQuery 跟随浏览器窗口的回到顶部按钮gototop(转)
    下载apachetomcat9.0.17windowsx64及安装以及用途
    J2SE基本安装和java的环境变量
    java简单的运算符和表达式
    关于类的成员,public,private修饰符
  • 原文地址:https://www.cnblogs.com/li-peng/p/5644594.html
Copyright © 2011-2022 走看看