zoukankan      html  css  js  c++  java
  • 第四章 功能初始化

    源代码GitHub:https://github.com/ZhaoRd/Zrd_0001_AuthorityManagement

    1.介绍

             对于权限管理系统来说,系统模块是必须的一部分,那么如何处理和收集模块信息是一个管家步骤,在没有看郭民峰的osharp之前,我能想到的都是通过管理员通过后台管理进行管理,osharp里采用attirbute的方式采集模块信息。该demo借鉴osharp的方式,通过使用attribute定义模块信息,程序启动时通过判断attribute进行模块和具体功能权限的信息收集。

            对于新采集的信息,如何判定这些新信息哪些是需要更新的,哪些是需要从已有信息中删除的,哪些又是需要新增的呢?这里需要使用到集合运算,具体请看以下内容。

    2.模块信息的定义

          在web中,操作一个功能的访问路径是 controller/action  ,在本demo中,一个controller就是一个功能,一个action就是一个具体的操作权限。在源代码中,定义SystemModelAttribute来定义功能信息,代码如下:

        /// <summary>
        /// 收集系统模块.
        /// </summary>
        public class SystemModelAttribute : Attribute
        {
            /// <summary>
            /// 模块名称.
            /// </summary>
            private string name;
            /// <summary>
            /// 分组名称.
            /// </summary>
            private string groupName;
            /// <summary>
            /// 只读模块名称.
            /// </summary>
            public string Name {
                get
                {
                    return this.name;
                }
            }
            /// <summary>
            /// 分组名称.
            /// </summary>
            public string GroupName {
                get
                {
                    return this.groupName;
                }
                set
                {
                    // 如果是通过构造函数初始化的名称,则其他设置均无效
                    if (string.IsNullOrEmpty(this.groupName))
                    {
                        this.groupName = value;    
                    }
                }
            }
            /// <summary>
            /// 模块的权限.
            /// </summary>
            private PermissionValue permissionValue;
            /// <summary>
            /// 模块的权限.
            /// </summary>
            public PermissionValue PermissionValue {
                get
                {
                    return this.permissionValue;
                }
            }
            /// <summary>
            /// Initializes a new instance of the <see cref="SystemModelAttribute"/> class.
            /// </summary>
            /// <param name="name">
            /// 模块名称.
            /// </param>
            /// <param name="permissionValue">
            /// 模块权限值.
            /// </param>
            /// <param name="groupName">
            /// 分组名称.
            /// </param>
            public SystemModelAttribute(string name, PermissionValue permissionValue = PermissionValue.All, string groupName = null)
            {
                this.name = name;
                this.groupName = groupName;
                this.permissionValue = permissionValue;
            }
        }  
    

      

    在controller上使用该attribute,即可定义一个模块,使用方式如下图

    6afc5dd7-8d80-4e4d-ae25-38aaec33ac2a

         SystemModelAttribute可以定义需要采集的模块信息,同理,可以在定义一个attribute,来定义需要采集的权限信息,源代码如下

    /// <summary>
        /// 权限信息设置,以便信息收集.
        /// </summary>
        public class PermissionSettingAttribute : Attribute
        {
            /// <summary>
            /// 具体权限.
            /// </summary>
            private readonly PermissionValue permissionValue;
            /// <summary>
            /// Initializes a new instance of the <see cref="PermissionSettingAttribute"/> class.
            /// </summary>
            /// <param name="value">
            /// The value.
            /// </param>
            public PermissionSettingAttribute(PermissionValue value)
            {
                this.permissionValue = value;
            }
            /// <summary>
            /// Gets the permission value.
            /// </summary>
            public PermissionValue PermissionValue
            {
                get
                {
                    return this.permissionValue;
                }
            }
        }
    

      

    使用方式如下:

    5a5066d9-335d-497c-8240-b8566f522ae2

    通过使用SystemModelAttribute和PermissionSettingAttribute来定义需要采集信息的内容.

    3.信息采集

             我们在Controller和Action上分别使用了不同的Attribute来定义信息,如何在代码中收集这些信息呢?主要代码如下

    1487c62d-78cd-4753-b05c-22371676db65

    首先是获取到Controller所在的程序集,然后根据获得的类型处理Type,具体的Invoke方法如下

      /// <summary>
            /// 解析Controller类型来收集Attribute信息.
            /// </summary>
            /// <param name="target">
            /// The target.
            /// </param>
            /// <returns>
            /// The <see cref="IEnumerable"/>.
            /// </returns>
            public IEnumerable<FunctionDto> Invoke(Type target)
            {
                var result = new List<FunctionDto>();
                var targetType = target;
                // 是否使用SystemModelAttribute
                if (!targetType.IsDefined(typeof(SystemModelAttribute), false))
                {
                    return result;
                }
                // 获取所有Controller里的方法
                var methods = targetType.GetMethods();
                // 获取功能模块的具体权限,必须是使用了PermissionSettingAttribute定义权限值,并取所有功能的并运算
                // 例如:一个Controller里只定义了Create和Edit,那么这个功能模块的权限就是 Create|Edit
                var functionPermissionValue = 
                    (from methodInfo in methods 
                     where methodInfo.IsDefined(typeof(PermissionSettingAttribute), false)
                     select methodInfo.GetCustomAttribute<PermissionSettingAttribute>()).Aggregate(
                         PermissionValue.None,
                         (current, permissionSetting) => current | permissionSetting.PermissionValue);
                // 获取SystemModelAttribute具体的信息
                var description = targetType.GetCustomAttribute<SystemModelAttribute>();
                var areaName = this.GetArea(target);
                var function = new FunctionDto()
                                   {
                                       FunctionName = description.Name,
                                       ModelName = areaName,
                                       PermissionValue = functionPermissionValue
                                   };
                result.Add(function);
                return result;
            }
    

      

    通过这样的一个函数,就可以采集到一个Controller里的权限信息,一个功能就是一个Controller,Controller里使用PermissionSettingAttribute定义的具体操作权限,所有定义的权限值取并运算,

    11db1eb7-7385-4e6c-8153-030138182abef0067c64-76b8-4641-afd9-8cf4f07374ab

    如图所示,一个Controller里包含Create和Edit,那么就说明这个功能模块的最大权限是Create|Edit,这样,在进行权限分配的时候,只能对该功能所具有的权限进行分配,未具有的权限不能分配.

    4. 信息处理

               经过上面的处理,那么功能信息和权限信息都已经采集到了,将这些信息保存到数据库,即可快捷方便的初始化系统的功能信息。

           在信息处理方面,主要使用了集合运算,为了对集合运算进行说明,我把已存在数据库里的功能信息集合定义为 A集合,新采集的集合定义为 B集合,那么对于B集合而言,怎么判断哪些是需要新添加到数据库,哪些是需要更新到数据库的,已存在数据库里的功能,哪些又是需要删除的呢?

           a.对于需要添加的功能,可以理解为存在B集合但是不存在A集合

           b.对于需要更新的功能,可以理解为即存在B集合又存在A集合

           c.对于需要删除的功能,可以理解为存在A集合中但是不存在B集合中

      从集合的角度来处理a  b  c三种情况,那么

           a.   B集合 减 A集合

           b.   B集合 交 A集合

           c.    A集合 减 B集合

       通过集合运算,就可以得到需要进行添加、更新、删除的功能信息了

      代码如下:

        /// <summary>
            /// 初始化系统功能.
            /// </summary>
            /// <param name="functionDtos">
            /// The function dtos.
            /// </param>
            public void InitModel(IEnumerable<FunctionDto> functionDtos)
            {
                var functions = this.functionRepository.FindAll().ToList();
                var addFunctions = functionDtos.Select(Mapper.Map<FunctionDto, Function>)
                    .AsEnumerable();
                // 创建如何判断两个function是否相等的条件
                var functionComparer = EqualityHelper<Function>.CreateComparer(m => m.ModelName + "#" + m.FunctionName);
                var enumerable = addFunctions as Function[] ?? addFunctions.ToArray();
                // 包含在将要处理的集合(addFunctions)
                // 但不包含在已经存在的集合(functions)
                // 表示需要添加到系统里的模块
                // 差集运算
                var toAddFunctions = enumerable.Except(functions, functionComparer);
                // 包含在已经存在的集合(functions)
                // 但不包含在将要处理的集合(addFunctions)
                // 表示需要从系统中删除的模块
                // 差集运算
                var toDeleteFunctions = functions.Except(enumerable, functionComparer);
                // 即包含在将要处理的集合(addFunctions)
                // 又包含在已经存在的集合(functions)
                // 表示需要更新内容
                // 交集运算
                var toUpdateFunctions = functions.Intersect(enumerable, functionComparer);
                LogHelper.Logger.Info(
                    string.Format(
                        "新增功能:{0}条;更新功能:{1}条;删除功能:{2};",
                        toAddFunctions.Count(),
                        toUpdateFunctions.Count(),
                        toDeleteFunctions.Count()));
                foreach (var addFunction in toAddFunctions)
                {
                    addFunction.ID = Guid.NewGuid();
                    var role = this.roleRepository.Find(
                        Specification<Role>.Eval(u => u.RoleName == "系统管理员"));
                    this.functionRepository.Add(addFunction);
                    // 初始化系统管理员的权限
                    this.functionInRoleRepository.Add(new FunctionInRole()
                    {
                        ID = GuidHelper.GenerateGuid(),
                        Function = addFunction,
                        PermissionValue = addFunction.PermissionValue,
                        Role = role
                    });
                }
                foreach (var deleteFunction in toDeleteFunctions)
                {
                    this.functionRepository.Remove(deleteFunction);
                }
                foreach (var updateFunction in toUpdateFunctions)
                {
                    var function = updateFunction;
                    var query = enumerable.Where(m => m.FunctionName == function.FunctionName);
                    var newValue = string.IsNullOrEmpty(updateFunction.ModelName) ? query.SingleOrDefault(u => u.ModelName == null) : query.SingleOrDefault(u => u.ModelName == function.ModelName);
                    if (newValue == null)
                    {
                        continue;
                    }
                    updateFunction.FunctionName = newValue.FunctionName;
                    updateFunction.ActionName = newValue.ActionName;
                    updateFunction.AreasName = newValue.AreasName;
                    updateFunction.ControllerName = newValue.ControllerName;
                    updateFunction.Description = newValue.Description;
                    updateFunction.ModelName = newValue.ModelName;
                    updateFunction.PermissionValue = newValue.PermissionValue;
                    this.functionRepository.Update(updateFunction);
                }
                this.functionInRoleRepository.Context.Commit();
            }
    

      

    5. 总结

              信息的定义和收集,主要是使用Attribute,该demo提供了一种使用Attribute的使用方式和方法。

              该篇还提供了一个使用集合进行处理数据的方式,扩展了我再处理集合时的一些思路,以前总是通过for 循环来处理两个集合,那么通过集合运算,可以很方便的得到集合信息。

    推荐QQ群:

    278252889(AngularJS中文社区)

    5008599(MVC EF交流群)

    134710707(ABP架构设计交流群 )

    59557329(c#基地 )

    230516560(.NET DDD基地 )

    本人联系方式:QQ:351157970

  • 相关阅读:
    用指针写线段树(维护乘法)
    费用流——网络流板子
    最小割板子题——[USACO5.4]奶牛的电信
    数论——置换
    NOIP2012 借教室
    POJ1990 moofest
    POJ2352 star
    POJ2299 Ultra-QuickSort
    CF498D Traffic Jams in the land
    POJ2828 Buy Ticket
  • 原文地址:https://www.cnblogs.com/zhaord/p/4865280.html
Copyright © 2011-2022 走看看