第四章 功能初始化

源代碼GitHub:https://github.com/ZhaoRd/Zrd_0001_AuthorityManagementgit

1.介紹

         對於權限管理系統來講,系統模塊是必須的一部分,那麼如何處理和收集模塊信息是一個管家步驟,在沒有看郭民峯的osharp以前,我能想到的都是經過管理員經過後臺管理進行管理,osharp裏採用attirbute的方式採集模塊信息。該demo借鑑osharp的方式,經過使用attribute定義模塊信息,程序啓動時經過判斷attribute進行模塊和具體功能權限的信息收集。github

        對於新採集的信息,如何斷定這些新信息哪些是須要更新的,哪些是須要從已有信息中刪除的,哪些又是須要新增的呢?這裏須要使用到集合運算,具體請看如下內容。web

 

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,便可定義一個模塊,使用方式以下圖c#

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;
            }
        }
    }

  

使用方式以下:app

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

經過使用SystemModelAttribute和PermissionSettingAttribute來定義須要採集信息的內容.函數

 

3.信息採集

         咱們在Controller和Action上分別使用了不一樣的Attribute來定義信息,如何在代碼中收集這些信息呢?主要代碼以下ui

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

首先是獲取到Controller所在的程序集,而後根據得到的類型處理Type,具體的Invoke方法以下this

  /// <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

相關文章
相關標籤/搜索