C# 权限管理方案

一、建立 SQL Server 数据库模型

 1、原始方案


  一共设立了五个实体模型:
 
  A、操作员(Operator):存储系统登录用户的名称、密码、启用状态等信息。
  B、权限组(RightsGroup):存储系统权限分组(即:权限角色)的名称等信息。
  C、权限关系(RightsRelation):用于将A项和B项之间的多对多关系拆解成两个一对多关系。
  D、权限列表(RightsList):存储系统菜单项(即:权限项)的标题、内部名称、权限状态等信息。
  E、权限组关系(RightGroupRelation):用于将B项和D项之间的多对多关系拆解成两个一对多关系。
  
  通过上面的描述可以清楚看到,C项和E项仅仅是为了拆解多对多关系而设立,实体关系变得相对复杂了点。稍作考虑便知,既然是使用 C# WinForm + SQL Server 来完成这一功能,则可以考虑使用实体类来模拟数据库模型,并将实体类打包成泛型集合后存储到 SQL Server 数据库的 varBinary(max) 字段。这样便可以将原始方案的数据库模型缩减成三个实体模型,降低了关系的复杂程度。将原始方案稍作修改后即可得到如下改进方案。
 
 2、改进方案
  
  如上所述,改进后的方案仅包含如下三个实体模型:
  
  A、操作员(Operator):存储系统登录用户的名称、密码、启用状态、权限集合等信息。
  B、权限组(RightsGroup):存储系统权限分组(即:权限角色)的名称、权限集合等信息。
  C、权限关系(RightsRelation):用于将A项和B项之间的多对多关系拆解成两个一对多关系。
  
  很容易看出,仅将原始方案的 E 项更改为 A项和 B 项的字段,即可将实体关系复杂度降低 40%。现在我们来看看改进方案的 SQL Server 数据库实现脚本代码:
 

-- 判断是否存在 操作员信息表(Operator),如果存在,则删除表 Operator
   if exists(Select * From SysObjects Where Name = 'Operator')
    Drop Table [Operator]
   Go 

   -- 创建 操作员信息表(Operator)
   Create Table [Operator]
   (
    -- 主键列,自动增长 标识种子为 1 
    [Id] int identity(1,1) Constraint [PK_OperatorId] Primary Key,

    -- 操作员姓名
    [OperatorName] nVarChar(50) Constraint [UQ_OperatorName] Unique(OperatorName) Not Null,

    -- 密码
    [Password] nVarChar(50) Constraint [CK_Password] Check(len([Password])>=6) Not Null,

    -- 操作员权限列表
    [RightsList] varBinary(max) Null,

    -- 用户当前状态
    [State] bit Constraint [DF_State] Default('true') Constraint [CK_State] Check([State] in ('true','false')) Not Null,
   )
   Go

   -- 判断是否存在 权限组信息表(RightsGroup),如果存在,则删除表 RightsGroup
   if exists(Select * From SysObjects Where Name = 'RightsGroup')
    Drop Table [RightsGroup]
   Go 

   -- 创建 权限组信息表(RightsGroup)
   Create Table [RightsGroup]
   (
    -- 主键列,自动增长 标识种子为 1 
    [Id] int Identity(1,1) Constraint [PK_RightsGroupId] Primary Key,
    
    -- 权限组名称
    [GroupName] nVarChar(50) Constraint[UQ_GroupName] Unique (GroupName) Not Null,

    -- 组权限列表
    [GroupRightsList] varBinary(max) Null,
   )
   Go

   -- 判断是否存在权限关系表(RightsRelation),如果存在,则删除表 RightsRelation
   if exists(Select * From SysObjects Where Name = 'RightsRelation')
    drop table [RightsRelation]
   Go

   -- 创建 权限关系表(RightsRelation)
   Create Table [RightsRelation]
   (
    -- 主键列,自动增长 标识种子为 1 
    [Id] int Identity(1, 1) Constraint [PK_RightsRelationId] Primary Key,

    -- 操作员 Id
    [OperatorId] int Constraint [FK_OperatorId] Foreign Key References Operator([Id]) Not Null,
    
    -- 权限组 Id
    [RightsGroupId] int Constraint [FK_RightsGroupId] Foreign Key References RightsGroup([Id]) Not Null
   )
   Go

二、建立实体类

 建立了 SQL Server 数据库模型之后,我们开始建立实体类来作为权限管理的数据传输载体。
 
 1、实体模型基类(ModelBase)
 
  C#源码清单:

using System;
using System.Collections.Generic;
using System.Text;

namespace CodingMouse.CMHotelManager.Model
{
    /// 
    ///  实体模型基类
    /// 
    [Serializable]
    public class ModelBase

    {
        #region Private Members

        int _id;
        string _modelName;

        #endregion

        #region Public Properties

        /// 
        /// 实体模型 ID
        /// 
        public int Id
        {
            get { return _id; }
            set { _id = value; }
        }

        /// 
        /// 实体模型名称
        /// 
        public string ModelName
        {
            get { return _modelName; }
            set { _modelName = value; }
        }
        #endregion

        #region Public Methods

        /// 
        /// 无参构造
        /// 
        public ModelBase() { } 

        /// 
        /// 带参构造
        /// 
        /// 实体模型 ID
        /// 实体模型名称
        public ModelBase(int id, string modelName)
        {
            this.Id = id;
            this.ModelName = modelName;
        }
        #endregion
    }
}

 2、操作员实体类(Operator)
 
  C#源码清单:

using System;
using System.Collections.Generic;
using System.Text;

namespace CodingMouse.CMHotelManager.Model
{
    /// 
    /// 操作员实体类
    /// 
    [Serializable]
    public class Operator : ModelBase
    {
        #region Private Members

        string _password;

        Dictionary<string, Rights> _rightsCollection;
        bool _state;

        #endregion

        #region Public Properties

        /// 
        /// 操作员密码
        /// 
        public string Password
        {
            get { return _password; }
            set { _password = value; }
        }

        /// 
        /// 权限集合(键值用于存储菜单/工具栏项的 Name 属性)
        /// 
        public Dictionary<string, Rights> RightsCollection
        {
            get { return _rightsCollection; }
            set { _rightsCollection = value; }
        }

        /// 
        /// 操作员状态
        /// 
        public bool State
        {
            get { return _state; }
            set { _state = value; }
        }
        #endregion

        #region Public Methods

        /// 
        /// 无参构造(基类属性赋值说明:Id - 操作员 ID / ModelName - 操作员名称)
        /// 
        public Operator() { }

        /// 
        /// 带参构造
        /// 
        /// 操作员 ID
        /// 操作员名称
        /// 操作员密码
        /// 权限集合(键值用于存储菜单/工具栏项的 Name 属性)
        /// 操作员状态
        public Operator(
        int operatorId,
        string name,
        string password,
        Dictionary<string, Rights> rightsCollection, bool state) : base(operatorId, name)
        {
            this.Password = password;
            this.RightsCollection = rightsCollection;
            this.State = state;
        }
        #endregion
    }
}

 3、权限组实体类(RightsGroup)
 
  C#源码清单:

using System;
using System.Collections.Generic;
using System.Text;

namespace CodingMouse.CMHotelManager.Model
{
    /// 
    /// 权限组实体类
    /// 
    [Serializable]
    public class RightsGroup : ModelBase
    {
        #region Private Members

        Dictionary<string, Rights> _groupRightsCollection;

        #endregion

        #region Public Properties

        /// 
        /// 组权限集合
        /// 
        public Dictionary<string, Rights> GroupRightsCollection
        {
            get { return _groupRightsCollection; }
            set { _groupRightsCollection = value; }
        }
        #endregion

        #region Public Methods

        /// 
        /// 无参构造(基类属性赋值说明:Id - 权限组 ID / ModelName - 权限组名称)
        /// 
        public RightsGroup() { }

        /// 
        ///  带参构造
        /// 
        /// 权限组 ID
        /// 权限组名称
        /// 组权限集合
        public RightsGroup(
        int groupId,
        string groupName,
        Dictionary<string, Rights> groupRightsCollection) : base(groupId, groupName)
        {
            this.GroupRightsCollection = groupRightsCollection;
        }
        #endregion
    }
}

 4、权限关系实体类(RightsRelation)
 
 C#源码清单:

using System;
using System.Collections.Generic;
using System.Text;

namespace CodingMouse.CMHotelManager.Model
{
    /// 
    /// 权限关系实体类
    /// 
    [Serializable]
    public class RightsRelation
    {
        #region Private Members

        int _id;

        int _operatorId;

        string _operatorName;

        int _rightsGroupId;

        string rightsGroupName;

        #endregion

        #region Public Properties

        /// 
        /// 权限关系 ID
        /// 
        public int Id
        {
            get { return _id; }
            set { _id = value; }
        }

        /// 
        ///  操作员 ID
        /// 
        public int OperatorId
        {
            get { return _operatorId; }
            set { _operatorId = value; }
        }

        /// 
        /// 操作员名称(便于在 WinForm 的 DataGridView 控件中实现数据绑定)
        /// 
        public string OperatorName
        {
            get { return _operatorName; }
            set { _operatorName = value; }
        }

        /// 
        /// 权限组 ID
        /// 
        public int RightsGroupId
        {
            get { return _rightsGroupId; }
            set { _rightsGroupId = value; }
        }

        /// 
        /// 权限组名称(便于在 WinForm 的 DataGridView 控件中实现数据绑定)
        /// 
        public string RightsGroupName
        {
            get { return rightsGroupName; }
            set { rightsGroupName = value; }
        }
        #endregion

        #region Public Methods

        /// 
        /// 无参构造 
        /// 
        public RightsRelation() { }

        /// 
        /// 带参构造
        /// 
        /// 权限关系 ID
        /// 操作员 ID
        /// 操作员名称
        /// 权限组 ID
        /// 权限组名称
        public RightsRelation(

        int id,

        int operatorId,

        string operatorName,

        int rightsGroupId,

        string rightsGroupName)
        {
            this.Id = id;

            this.OperatorId = operatorId;

            this.OperatorName = operatorName;

            this.RightsGroupId = rightsGroupId;

            this.RightsGroupName = rightsGroupName;
        }
        #endregion
    }
}

三、具体代码实现

 采用多层开发模式有助于降低耦合度,便于程序维护。所以,我们的本文的具体代码实现也使用了多层开发模式。限于篇幅,只列举出具体的代码实现类源码。同时,也是由于本文并不是讲解多层开发的文章,所以对于完成本文的主题功能所涉及的简单工厂、抽象工厂、接口定义、数据库访问等类的源码就不再一一罗列。
 
 (一)数据访问层
 
 1、操作员数据访问操作类(OperatorService)
 
 C#源码清单:
 

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Runtime.Serialization.Formatters.Binary;
using DBUtility = CodingMouse.CMHotelManager.DBUtility;
using IDAL = CodingMouse.CMHotelManager.IDAL;
using Model = CodingMouse.CMHotelManager.Model;

namespace CodingMouse.CMHotelManager.DAL
{
    /// 
    /// 操作员数据访问操作类
    /// 
    public class OperatorService : IDAL.IOperatorService
    {
        #region IOperatorService 成员

        /// 
        /// 根据操作员名称和密码获取操作员实体
        /// 
        /// 操作员名称
        /// 操作员密码
        /// 操作员实体
        public Model.Operator GetOperatorInfoByName(string name, string pwd)
        {
            //SQL命令
            string sqltxt = string.Format("Select Id, OperatorName, Password, RightsList, State From Operator Where OperatorName = '{0}' And Password = '{1}'", name, pwd);

            //创建操作员实体
            Model.Operator tmpOperator = new Model.Operator();

            // 转换数据库存储的 二进制数据为 Byte[] 数组 以便进而转换为操作员权限集合
            // 从配置文件读取连接字符串
            string connectionString = ConfigurationManager.ConnectionStrings["SQLSERVER"].ConnectionString;

            // 执行 SQL 命令
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                SqlCommand cmd = new SqlCommand(sqltxt, conn);
                conn.Open();

                using (SqlDataReader myReader = cmd.ExecuteReader(
                CommandBehavior.CloseConnection |
                CommandBehavior.SingleResult |
                CommandBehavior.SingleRow))
                {
                    if (myReader.Read())
                    {
                        //将数据集转换成实体集合
                        tmpOperator.Id = Convert.ToInt32(myReader["Id"]);
                        tmpOperator.ModelName = Convert.ToString(myReader["OperatorName"]);
                        tmpOperator.Password = Convert.ToString(myReader["Password"]);
                        tmpOperator.State = Convert.ToBoolean(myReader["State"]);

                        // 读取权限集合
                        System.Data.SqlTypes.SqlBytes bytes = myReader.GetSqlBytes(3); // 只能指定列序号

                        // 将流反序列化为权限集合对象
                        BinaryFormatter bf = new BinaryFormatter();
                        if (!bytes.IsNull)
                            tmpOperator.RightsCollection = (bf.Deserialize(bytes.Stream) as Dictionary<string, Model.Rights>);
                        //else
                        // throw new Exception(string.Format("操作员 [{0}] 没有任何权限,禁止登录!", tmpOperator.ModelName));
                    }
                    else
                        //如果没有读取到内容则抛出异常
                        throw new Exception("登录名称或用户密码不正确!");
                }
            }

            // 如果操作员已经被禁用
            if (!tmpOperator.State)
                throw new Exception(string.Format("操作员 [{0}] 已被禁用,请与管理员联系!", tmpOperator.ModelName));
            // 返回结果
            return tmpOperator;
        }

        /// 
        /// 添加操作员
        /// 
        /// 要添加的操作员实体
        /// True:成功/False:失败
        public bool AddOperator(Model.Operator addOperator)
        {
            // 验证密码长度
            if (addOperator.Password.Trim().Length < 6)
                throw new Exception("用户密码长度不能小于六位!");

            // 转换操作员权限集合为数据库可存取的 Byte[] 数组
            MemoryStream ms = new MemoryStream();
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, addOperator.RightsCollection);
            byte[] rigthsByteArray = new byte[(int)(ms.Length)];
            ms.Position = 0;
            ms.Read(rigthsByteArray, 0, (int)(ms.Length));
            ms.Close();

            // 拼接 SQL 命令
            string sqlTxt = "Insert Into Operator (OperatorName, Password, RightsList, State) Values (@OperatorName, @Password, @RightsList, @State)";

            // 从配置文件读取连接字符串
            string connectionString = ConfigurationManager.ConnectionStrings["SQLSERVER"].ConnectionString;

            // 执行 SQL 命令
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                SqlCommand cmd = new SqlCommand(sqlTxt, conn);
                SqlParameter prm1 = new SqlParameter("@OperatorName", SqlDbType.NVarChar, 50);
                prm1.Value = addOperator.ModelName;
                SqlParameter prm2 = new SqlParameter("@Password", SqlDbType.NVarChar, 50);
                prm2.Value = addOperator.Password;
                SqlParameter prm3 = new SqlParameter("@RightsList", SqlDbType.VarBinary, rigthsByteArray.Length,
                ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Current, rigthsByteArray);
                SqlParameter prm4 = new SqlParameter("@State", SqlDbType.Bit);
                prm4.Value = addOperator.State;
                cmd.Parameters.AddRange(new SqlParameter[] { prm1, prm2, prm3, prm4 });
                conn.Open();

                if (cmd.ExecuteNonQuery() >= 1)
                    return true;
                else
                    return false;
            }
        }

        /// 
        /// 删除操作员
        /// 
        /// 要删除的操作员 ID
        /// True:成功/False:失败
        public bool DeleteOperatorByID(int id)
        {
            // 删除单个信息 SQL 命令
            string sqlTxt = string.Format("Delete From Operator Where Id = {0}", id);

            // 创建 SQL 执行对象
            DBUtility.AbstractDBProvider dbProvider = DBUtility.AbstractDBProvider.Instance();

            // 执行 删除操作
            int rowsAffected;
            dbProvider.RunCommand(sqlTxt, out rowsAffected);

            if (rowsAffected >= 1)
                return true;
            else
                return false;
        }

        public bool ModifyOperator(Model.Operator currentOperator)
        {
            // 验证密码长度
            if (currentOperator.Password.Trim().Length < 6)
                throw new Exception("用户密码长度不能小于六位!");

            // 转换操作员权限集合为数据库可存取的 Byte[] 数组
            MemoryStream ms = new MemoryStream();
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, currentOperator.RightsCollection);
            byte[] rigthsByteArray = new byte[(int)(ms.Length)];
            ms.Position = 0;
            ms.Read(rigthsByteArray, 0, (int)(ms.Length));
            ms.Close();

            // 拼接 SQL 命令
            string sqlTxt = "Update Operator Set OperatorName = @OperatorName, Password = @Password, RightsList = @RightsList, State = @State Where Id = @Id";

            // 从配置文件读取连接字符串
            string connectionString = ConfigurationManager.ConnectionStrings["SQLSERVER"].ConnectionString;

            // 执行 SQL 命令
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                SqlCommand cmd = new SqlCommand(sqlTxt, conn);
                SqlParameter prm1 = new SqlParameter("@OperatorName", SqlDbType.NVarChar, 50);
                prm1.Value = currentOperator.ModelName;
                SqlParameter prm2 = new SqlParameter("@Password", SqlDbType.NVarChar, 50);
                prm2.Value = currentOperator.Password;
                SqlParameter prm3 = new SqlParameter("@RightsList", SqlDbType.VarBinary, rigthsByteArray.Length,
                ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Current, rigthsByteArray);
                SqlParameter prm4 = new SqlParameter("@State", SqlDbType.Bit);
                prm4.Value = currentOperator.State;
                SqlParameter prm5 = new SqlParameter("@Id", SqlDbType.Int);
                prm5.Value = currentOperator.Id;
                cmd.Parameters.AddRange(new SqlParameter[] { prm1, prm2, prm3, prm4, prm5 });
                conn.Open();

                if (cmd.ExecuteNonQuery() >= 1)
                    return true;
                else
                    return false;
            }
        }

        /// 
        /// 获取所有操作员信息
        /// 
        /// 操作员实体集合
        public Dictionary<string, Model.Operator> GetAllOperatorInfo()
        {
            //SQL命令
            string sqltxt = "Select Id, OperatorName, Password, RightsList, State From Operator";
            //创建操作员实体集合
            Dictionary<string, Model.Operator> operatorCollection = new Dictionary<string, Model.Operator>();
            //定义操作员实体
            Model.Operator tmpOperator = null;

            // 转换数据库存储的 二进制数据为 Byte[] 数组 以便进而转换为操作员权限集合
            // 从配置文件读取连接字符串
            string connectionString = ConfigurationManager.ConnectionStrings["SQLSERVER"].ConnectionString;
            // 执行 SQL 命令
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                SqlCommand cmd = new SqlCommand(sqltxt, conn);
                conn.Open();
                using (SqlDataReader myReader = cmd.ExecuteReader(
                CommandBehavior.CloseConnection))
                {
                    while (myReader.Read())
                    {
                        // 创建操作员实体
                        tmpOperator = new Model.Operator();
                        //将数据集转换成实体集合
                        tmpOperator.Id = Convert.ToInt32(myReader["Id"]);
                        tmpOperator.ModelName = Convert.ToString(myReader["OperatorName"]);
                        tmpOperator.Password = Convert.ToString(myReader["Password"]);
                        tmpOperator.State = Convert.ToBoolean(myReader["State"]);

                        // 读取权限集合
                        System.Data.SqlTypes.SqlBytes bytes = myReader.GetSqlBytes(3); // 只能指定列序号
                        // 将流反序列化为权限集合对象
                        BinaryFormatter bf = new BinaryFormatter();
                        if (!bytes.IsNull)
                            tmpOperator.RightsCollection = (bf.Deserialize(bytes.Stream) as Dictionary<string, Model.Rights>);

                        // 添加到操作员实体集合
                        operatorCollection.Add(tmpOperator.ModelName, tmpOperator);
                    }
                }
            }

            // 返回结果
            return operatorCollection;
        }

        /// 
        /// 根据操作员名称校验操作员是否存在
        /// 
        /// 操作员名称
        /// True:存在/Flase:不存在
        public bool CheckOperatorExist(string operatorName)
        {
            //创建查询信息的 SQL
            string sqlTxt = string.Format("Select Count(*) From Operator Where OperatorName = '{0}'",
            operatorName);

            //创建SQL执行对象
            DBUtility.AbstractDBProvider dbProvider = DBUtility.AbstractDBProvider.Instance();

            //执行查询操作
            int result = Convert.ToInt32(dbProvider.RunCommand(sqlTxt));
            if (result >= 1)
                return true;
            else
                return false;
        }
        #endregion
    }
}

 2、权限组数据访问操作类(RightsGroupService)
 
 C#源码清单:

 using System;
 using System.Collections.Generic;
 using System.Text;
 using System.IO;
 using System.Data;
 using System.Data.SqlClient;
 using System.Configuration;
 using System.Runtime.Serialization.Formatters.Binary;
 using DBUtility = CodingMouse.CMHotelManager.DBUtility;
 using IDAL = CodingMouse.CMHotelManager.IDAL;
 using Model = CodingMouse.CMHotelManager.Model;

 namespace CodingMouse.CMHotelManager.DAL
 {
  ///  
  /// 权限组数据访问操作类 
  ///  
  public class RightsGroupService : IDAL.IRightsGroupService
  { 
   #region IRightsGroupService 成员 

   ///  
   /// 获取所有权限组信息 
   ///  
   /// 权限组实体集合 
   public Dictionary<string, Model.RightsGroup> GetAllRightsGroupInfo()
   {
    //SQL命令 
    string sqltxt = "Select Id, GroupName, GroupRightsList From RightsGroup";
    //创建权限组实体集合 
    Dictionary<string, Model.RightsGroup> rightsGroupCollection = new Dictionary<string, Model.RightsGroup>();
    //定义权限组实体 
    Model.RightsGroup tmpRightsGroup = null;

    // 转换数据库存储的 二进制数据为 Byte[] 数组 以便进而转换为权限组权限集合 
    // 从配置文件读取连接字符串 
    string connectionString = ConfigurationManager.ConnectionStrings["SQLSERVER"].ConnectionString;
    // 执行 SQL 命令 
    using (SqlConnection conn = new SqlConnection(connectionString))
    {
     SqlCommand cmd = new SqlCommand(sqltxt, conn);
     conn.Open();

     using (SqlDataReader myReader = cmd.ExecuteReader(
      CommandBehavior.CloseConnection))
     {
      while (myReader.Read())
      {
       // 创建权限组实体 
       tmpRightsGroup = new Model.RightsGroup();
       //将数据集转换成实体集合 
       tmpRightsGroup.Id = Convert.ToInt32(myReader["Id"]);
       tmpRightsGroup.ModelName = Convert.ToString(myReader["GroupName"]);

       // 读取权限集合 
       System.Data.SqlTypes.SqlBytes bytes = myReader.GetSqlBytes(2); // 只能指定列序号 
       // 将流反序列化为权限集合对象 
       BinaryFormatter bf = new BinaryFormatter();
       if (!bytes.IsNull)
        tmpRightsGroup.GroupRightsCollection = (bf.Deserialize(bytes.Stream) as Dictionary<string, Model.Rights>);

       // 添加到权限组实体集合 
       rightsGroupCollection.Add(tmpRightsGroup.ModelName, tmpRightsGroup);
      }
     }
    }

    // 返回结果 
    return rightsGroupCollection;
   }

   ///  
   /// 添加权限组 
   ///  
   /// 要添加的权限组实体 
   /// True:成功/False:失败 
   public bool AddRightsGroup(Model.RightsGroup addRightsGroup)
   {
    // 转换权限组权限集合为数据库可存取的 Byte[] 数组 
    MemoryStream ms = new MemoryStream();
    BinaryFormatter bf = new BinaryFormatter();
    bf.Serialize(ms, addRightsGroup.GroupRightsCollection);
    byte[] rigthsByteArray = new byte[(int)(ms.Length)];
    ms.Position = 0;
    ms.Read(rigthsByteArray, 0, (int)(ms.Length));
    ms.Close();

    // 拼接 SQL 命令 
    string sqlTxt = "Insert Into RightsGroup (GroupName, GroupRightsList) Values " +
     "(@GroupName, @GroupRightsList)";

    // 从配置文件读取连接字符串 
    string connectionString = ConfigurationManager.ConnectionStrings["SQLSERVER"].ConnectionString;
    // 执行 SQL 命令 
    using (SqlConnection conn = new SqlConnection(connectionString))
    {
     SqlCommand cmd = new SqlCommand(sqlTxt, conn);
     SqlParameter prm1 = new SqlParameter("@GroupName", SqlDbType.NVarChar, 50);
     prm1.Value = addRightsGroup.ModelName;
     SqlParameter prm2 = new SqlParameter("@GroupRightsList", SqlDbType.VarBinary, rigthsByteArray.Length,
      ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Current, rigthsByteArray);

     cmd.Parameters.AddRange(new SqlParameter[] { prm1, prm2 });
     conn.Open();

     if (cmd.ExecuteNonQuery() >= 1)
      return true;
     else
      return false;
    }
   }

   ///  
   /// 删除权限组 
   ///  
   /// 要删除的权限组 ID 
   /// True:成功/False:失败 
   public bool DeleteRightsGroupByID(int id)
   {
    // 删除单个信息 SQL 命令 
    string sqlTxt = string.Format("Delete From RightsGroup Where Id = {0}", id);
    // 创建 SQL 执行对象 
    DBUtility.AbstractDBProvider dbProvider = DBUtility.AbstractDBProvider.Instance();
    // 执行 删除操作 
    int rowsAffected;
    dbProvider.RunCommand(sqlTxt, out rowsAffected);

    if (rowsAffected >= 1)
     return true;
    else
     return false;
   }

   ///  
   /// 修改权限组 
   ///  
   /// 要修改的权限组实体 
   /// True:成功/False:失败 
   public bool ModifyRightsGroup(Model.RightsGroup currentRightsGroup)
   {
    // 转换权限组权限集合为数据库可存取的 Byte[] 数组 
    MemoryStream ms = new MemoryStream();
    BinaryFormatter bf = new BinaryFormatter();
    bf.Serialize(ms, currentRightsGroup.GroupRightsCollection);
    byte[] rigthsByteArray = new byte[(int)(ms.Length)];
    ms.Position = 0;
    ms.Read(rigthsByteArray, 0, (int)(ms.Length));
    ms.Close();

    // 拼接 SQL 命令 
    string sqlTxt = "Update RightsGroup Set GroupName = @GroupName, GroupRightsList = @GroupRightsList Where Id = @Id";

    // 从配置文件读取连接字符串 
    string connectionString = ConfigurationManager.ConnectionStrings["SQLSERVER"].ConnectionString;
    // 执行 SQL 命令 
    using (SqlConnection conn = new SqlConnection(connectionString))
    {
     SqlCommand cmd = new SqlCommand(sqlTxt, conn);
     SqlParameter prm1 = new SqlParameter("@GroupName", SqlDbType.NVarChar, 50);
     prm1.Value = currentRightsGroup.ModelName;
     SqlParameter prm2 = new SqlParameter("@GroupRightsList", SqlDbType.VarBinary, rigthsByteArray.Length,
      ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Current, rigthsByteArray);
     SqlParameter prm3 = new SqlParameter("@Id", SqlDbType.Int);
     prm3.Value = currentRightsGroup.Id;

     cmd.Parameters.AddRange(new SqlParameter[] { prm1, prm2, prm3 });
     conn.Open();

     if (cmd.ExecuteNonQuery() >= 1)
      return true;
     else
      return false;
    }
   }

   ///  
   /// 根据权限组名称校验权限组是否已经存在 
   ///  
   /// 权限组名称 
   /// True:存在/False:不存在 
   public bool CheckRightsGroupExist(string rightsGroupName)
   {
    //SQL命令 
    string sqlTxt = string.Format("Select Count(*) From RightsGroup Where GroupName = '{0}'", rightsGroupName);

    //创建SQL执行对象 
    DBUtility.AbstractDBProvider dbProvider = DBUtility.AbstractDBProvider.Instance();
    //执行查询操作 
    int result = Convert.ToInt32(dbProvider.RunCommand(sqlTxt));

    if (result >= 1)
     return true;
    else
     return false;
   } 

   #endregion 
  }
 }

 3、权限关系数据访问操作类(RightsRelationService)

 C#源码清单:

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using DBUtility = CodingMouse.CMHotelManager.DBUtility;
using IDAL = CodingMouse.CMHotelManager.IDAL;
using Model = CodingMouse.CMHotelManager.Model;

namespace CodingMouse.CMHotelManager.DAL
{
    /// 
    /// 权限关系数据访问操作类
    /// 
    public class RightsRelationService : IDAL.IRightsRelationService
    {
        #region IRightsRelationService 成员

        /// 
        /// 添加单个权限关系
        /// 
        /// 权限关系实体
        /// True:成功/False:失败
        public bool AddRightsRelation(Model.RightsRelation rightsRelation)
        {
            // 拼接 SQL 命令
            string sqlTxt = string.Format("Insert Into RightsRelation (OperatorId, RightsGroupId) Values ({0}, {1})",
            rightsRelation.OperatorId, rightsRelation.RightsGroupId);

            // 创建 SQL 执行对象
            DBUtility.AbstractDBProvider dbProvider = DBUtility.AbstractDBProvider.Instance();

            // 执行 SQL
            int rowsAffected;
            dbProvider.RunCommand(sqlTxt, out rowsAffected);
            if (rowsAffected == 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// 
        /// 根据权限关系 ID 删除权限关系
        /// 
        /// 权限关系 ID
        ///  True:成功/False:失败
        public bool DeleteRightsRelationById(int id)
        {
            bool isOk = false;

            // 删除单个信息 SQL 命令
            string sqlTxt = string.Format("Delete From RightsRelation Where Id = {0}", id);

            // 创建 SQL 执行对象
            DBUtility.AbstractDBProvider dbProvider = DBUtility.AbstractDBProvider.Instance();

            // 执行 删除操作
            int rowsAffected;
            dbProvider.RunCommand(sqlTxt, out rowsAffected);
            if (rowsAffected >= 1)
            {
                isOk = true;
            }
            else
            {
                isOk = false;
            }
            return isOk;
        }

        /// 
        /// 根据操作员 ID 删除对应的所有权限关系
        /// 
        /// 操作员 ID
        /// True:成功/False:失败
        public bool DeleteRightsRelationByOperatorId(int operatorId)
        {
            bool isOk = false;

            // 删除单个信息 SQL 命令
            string sqlTxt = string.Format("Delete From RightsRelation Where OperatorId = {0}", operatorId);

            // 创建 SQL 执行对象
            DBUtility.AbstractDBProvider dbProvider = DBUtility.AbstractDBProvider.Instance();

            // 执行 删除操作
            int rowsAffected;
            dbProvider.RunCommand(sqlTxt, out rowsAffected);
            if (rowsAffected >= 1)
            {
                isOk = true;
            }
            else
            {
                isOk = false;
            }
            return isOk;
        }

        /// 
        /// 修改单个权限关系
        /// 
        /// 权限关系实体
        /// True:成功/False:失败
        public bool ModifyRightsRelation(Model.RightsRelation rightsRelation)
        {
            // 拼接 SQL 命令
            string sqlTxt = string.Format("Update RightsRelation Set OperatorId = {0}, RightsGroupId = {1} Where Id = {2}",
            rightsRelation.OperatorId, rightsRelation.RightsGroupId, rightsRelation.Id);

            // 创建 SQL 执行对象
            DBUtility.AbstractDBProvider dbProvider = DBUtility.AbstractDBProvider.Instance();

            // 执行 SQL
            int rowsAffected;
            dbProvider.RunCommand(sqlTxt, out rowsAffected);
            if (rowsAffected == 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// 
        /// 获取所有的权限关系集合
        /// 
        /// 权限关系集合
        public List GetAllRightsRelation()
        {
            //创建数据集
            DataSet dsRightsRelation = new DataSet("RightsRelation");

            //创建客户集合
            List rightsRelationList = new List();

            //创建查询客户信息的 SQL
            string sqlTxt = "Select R.Id, R.OperatorId, O.OperatorName, R.RightsGroupId, G.GroupName As [RightsGroupName] From RightsRelation As R Join Operator As O On R.OperatorId = O.Id Join RightsGroup As G On R.RightsGroupId = G.Id";

            //创建SQL执行对象
            DBUtility.AbstractDBProvider dbProvider = DBUtility.AbstractDBProvider.Instance();

            //执行查询操作
            dsRightsRelation = dbProvider.RunCommand(sqlTxt, "RightsRelation");

            //将数据集转换成实体集合
            foreach (DataRow row in dsRightsRelation.Tables["RightsRelation"].Rows)
            {
                Model.RightsRelation tmpRightsRelation = new Model.RightsRelation();
                tmpRightsRelation.Id = Convert.ToInt32(row["Id"]);
                tmpRightsRelation.OperatorId = Convert.ToInt32(row["OperatorId"]);
                tmpRightsRelation.OperatorName = Convert.ToString(row["OperatorName"]);
                tmpRightsRelation.RightsGroupId = Convert.ToInt32(row["RightsGroupId"]);
                tmpRightsRelation.RightsGroupName = Convert.ToString(row["RightsGroupName"]);
                rightsRelationList.Add(tmpRightsRelation);
            }

            //返回所有客户集合
            return rightsRelationList;
        }

        /// 
        /// 根据操作员 ID 获取对应的所有权限关系
        /// 
        /// 操作员 ID
        /// 权限关系集合
        public List GetRightsRelationByOperatorId(int id)
        {
            //创建数据集
            DataSet dsRightsRelation = new DataSet("RightsRelation");

            //创建客户集合
            List rightsRelationList = new List();

            //创建查询客户信息的 SQL
            string sqlTxt = string.Format("Select R.Id, R.OperatorId, O.OperatorName, R.RightsGroupId, G.GroupName As [RightsGroupName] From RightsRelation As R Join Operator As O " +

            "On R.OperatorId = O.Id Join RightsGroup As G On R.RightsGroupId = G.Id Where OperatorId = {0}", id);

            //创建SQL执行对象
            DBUtility.AbstractDBProvider dbProvider = DBUtility.AbstractDBProvider.Instance();

            //执行查询操作
            dsRightsRelation = dbProvider.RunCommand(sqlTxt, "RightsRelation");

            //将数据集转换成实体集合
            foreach (DataRow row in dsRightsRelation.Tables["RightsRelation"].Rows)
            {
                Model.RightsRelation tmpRightsRelation = new Model.RightsRelation();
                tmpRightsRelation.Id = Convert.ToInt32(row["Id"]);
                tmpRightsRelation.OperatorId = Convert.ToInt32(row["OperatorId"]);
                tmpRightsRelation.OperatorName = Convert.ToString(row["OperatorName"]);
                tmpRightsRelation.RightsGroupId = Convert.ToInt32(row["RightsGroupId"]);
                tmpRightsRelation.RightsGroupName = Convert.ToString(row["RightsGroupName"]);
                rightsRelationList.Add(tmpRightsRelation);
            }
            //返回所有关系集合
            return rightsRelationList;
        }

        /// 
        /// 根据权限组 ID 获取与此权限组相关的权限关系数量
        /// 
        /// 权限组 ID
        /// 权限关系数量
        public int GetRightsRelationCountByRightsGroupId(int id)
        {
            // SQL命令
            string sqlTxt = string.Format("Select Count(*) From RightsRelation Where RightsGroupId = {0}", id);

            // 创建SQL执行对象
            DBUtility.AbstractDBProvider dbProvider = DBUtility.AbstractDBProvider.Instance();

            // 执行查询操作
            int result = Convert.ToInt32(dbProvider.RunCommand(sqlTxt));

            // 返回结果
            return result;
        }
        #endregion
    }
}

 (二)业务逻辑层(在本文中仅仅起到一个数据传递者的作用)
 
 1、操作员数据访问操作类(OperatorManager)
 
 C#源代码清单

using System;
using System.Collections.Generic;
using System.Text;
using DALFactory = CodingMouse.CMHotelManager.DALFactory;
using IBLL = CodingMouse.CMHotelManager.IBLL;
using IDAL = CodingMouse.CMHotelManager.IDAL;
using Model = CodingMouse.CMHotelManager.Model;

namespace CodingMouse.CMHotelManager.BLL
{
    /// 
    /// 操作员数据访问操作类
    /// 
    public class OperatorManager : IBLL.IOperatorManager
    {
        #region IOperatorManager 成员

        /// 
        /// 根据操作员名称和密码获取操作员实体
        /// 
        /// 操作员名称
        /// 操作员密码
        /// 操作员实体
        public Model.Operator GetOperatorInfoByName(string name, string pwd)
        {
            // 超级后门管理员账户(测试用,千万别用于商业用途,要不然被抓去坐监可别怪我!)
            if (name == "CodingMouse" && pwd == "20071117")
            {
                Model.Operator adminOperator = new Model.Operator();
                adminOperator.Id = 0;
                adminOperator.ModelName = name;
                adminOperator.Password = pwd;
                adminOperator.RightsCollection = new Dictionary<string, Model.Rights>();
                adminOperator.State = true;
                return adminOperator;
            }
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();

            //调用工厂方法生成实例
            IDAL.IOperatorService operatorService = absDALFactory.BuildOperatorService();

            //调用实例方法
            return operatorService.GetOperatorInfoByName(name, pwd);
        }

        /// 
        /// 添加操作员
        /// 
        /// 要添加的操作员实体
        /// True:成功/False:失败
        public bool AddOperator(Model.Operator addOperator)
        {
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();
            //调用工厂方法生成实例
            IDAL.IOperatorService operatorService = absDALFactory.BuildOperatorService();
            //调用实例方法
            return operatorService.AddOperator(addOperator);
        }

        /// 
        /// 删除操作员
        /// 
        /// 要删除的操作员 ID
        /// True:成功/False:失败
        public bool DeleteOperatorByID(int id)
        {
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();
            //调用工厂方法生成实例
            IDAL.IOperatorService operatorService = absDALFactory.BuildOperatorService();
            //调用实例方法
            return operatorService.DeleteOperatorByID(id);
        }

        /// 
        /// 修改操作员
        /// 
        /// 要修改的操作员实体
        /// True:成功/False:失败
        public bool ModifyOperator(Model.Operator currentOperator)
        {
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();
            //调用工厂方法生成实例
            IDAL.IOperatorService operatorService = absDALFactory.BuildOperatorService();
            //调用实例方法
            return operatorService.ModifyOperator(currentOperator);
        }

        /// 
        /// 获取所有操作员信息
        /// 
        /// 操作员实体集合
        public Dictionary<string, Model.Operator> GetAllOperatorInfo()
        {
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();
            //调用工厂方法生成实例
            IDAL.IOperatorService operatorService = absDALFactory.BuildOperatorService();
            //调用实例方法
            return operatorService.GetAllOperatorInfo();
        }

        /// 
        /// 根据操作员名称校验操作员是否存在
        /// 
        /// 操作员名称
        /// True:存在/Flase:不存在
        public bool CheckOperatorExist(string operatorName)
        {
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();
            //调用工厂方法生成实例
            IDAL.IOperatorService operatorService = absDALFactory.BuildOperatorService();
            //调用实例方法
            return operatorService.CheckOperatorExist(operatorName);
        }
        #endregion
    }
}

 2、权限组数据访问操作类(RightsGroupManager)
 
 C#源码清单:

using System;
using System.Collections.Generic;
using System.Text;
using DALFactory = CodingMouse.CMHotelManager.DALFactory;
using IBLL = CodingMouse.CMHotelManager.IBLL;
using IDAL = CodingMouse.CMHotelManager.IDAL;
using Model = CodingMouse.CMHotelManager.Model;

namespace CodingMouse.CMHotelManager.BLL
{
    /// 
    /// 权限组数据访问操作类
    /// 
    public class RightsGroupManager : IBLL.IRightsGroupManager
    {
        #region IRightsGroupManager 成员

        /// 
        /// 获取所有权限组信息
        /// 
        /// 权限组实体集合
        public Dictionary<string, Model.RightsGroup> GetAllRightsGroupInfo()
        {
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();
            //调用工厂方法生成实例
            IDAL.IRightsGroupService rightsGroupService = absDALFactory.BuildRightsGroupService();
            //调用实例方法
            return rightsGroupService.GetAllRightsGroupInfo();
        }

        /// 
        /// 添加权限组
        /// 
        /// 要添加的权限组实体
        /// True:成功/False:失败
        public bool AddRightsGroup(Model.RightsGroup addRightsGroup)
        {
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();
            //调用工厂方法生成实例
            IDAL.IRightsGroupService rightsGroupService = absDALFactory.BuildRightsGroupService();
            //调用实例方法
            return rightsGroupService.AddRightsGroup(addRightsGroup);
        }

        /// 
        /// 删除权限组
        /// 
        /// 要删除的权限组 ID
        /// True:成功/False:失败
        public bool DeleteRightsGroupByID(int id)
        {
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();
            //调用工厂方法生成实例
            IDAL.IRightsGroupService rightsGroupService = absDALFactory.BuildRightsGroupService();
            //调用实例方法
            return rightsGroupService.DeleteRightsGroupByID(id);
        }

        /// 
        /// 修改权限组
        /// 
        /// 要修改的权限组实体
        ///  True:成功/False:失败
        public bool ModifyRightsGroup(Model.RightsGroup currentRightsGroup)
        {
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();
            //调用工厂方法生成实例
            IDAL.IRightsGroupService rightsGroupService = absDALFactory.BuildRightsGroupService();
            //调用实例方法
            return rightsGroupService.ModifyRightsGroup(currentRightsGroup);
        }

        /// 
        /// 根据权限组名称校验权限组是否已经存在
        /// 
        /// 权限组名称
        /// True:存在/False:不存在
        public bool CheckRightsGroupExist(string rightsGroupName)
        {
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();
            //调用工厂方法生成实例
            IDAL.IRightsGroupService rightsGroupService = absDALFactory.BuildRightsGroupService();
            //调用实例方法
            return rightsGroupService.CheckRightsGroupExist(rightsGroupName);
        }
        #endregion
    }
}

 3、权限关系数据访问操作类(RightsRelationManager)
 
 C#源码清单:

using System;
using System.Collections.Generic;
using System.Text;
using DALFactory = CodingMouse.CMHotelManager.DALFactory;
using IBLL = CodingMouse.CMHotelManager.IBLL;
using IDAL = CodingMouse.CMHotelManager.IDAL;
using Model = CodingMouse.CMHotelManager.Model;

namespace CodingMouse.CMHotelManager.BLL
{
    /// 
    /// 权限关系数据访问操作类
    /// 
    public class RightsRelationManager : IBLL.IRightsRelationManager
    {
        #region IRightsRelationManager 成员

        /// 
        ///  添加单个权限关系
        /// 
        /// 权限关系实体
        /// True:成功/False:失败
        public bool AddRightsRelation(Model.RightsRelation rightsRelation)
        {
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();
            //调用工厂方法生成实例
            IDAL.IRightsRelationService rightsRelationService = absDALFactory.BuildRightsRelationService();
            //调用实例方法
            return rightsRelationService.AddRightsRelation(rightsRelation);
        }

        /// 
        /// 根据权限关系 ID 删除权限关系
        /// 
        /// 权限关系 ID
        ///  True:成功/False:失败
        public bool DeleteRightsRelationById(int id)
        {
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();
            //调用工厂方法生成实例
            IDAL.IRightsRelationService rightsRelationService = absDALFactory.BuildRightsRelationService();
            //调用实例方法
            return rightsRelationService.DeleteRightsRelationById(id);
        }

        /// 
        /// 根据操作员 ID 删除对应的所有权限关系
        /// 
        /// 操作员 ID
        /// True:成功/False:失败
        public bool DeleteRightsRelationByOperatorId(int operatorId)
        {
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();
            //调用工厂方法生成实例
            IDAL.IRightsRelationService rightsRelationService = absDALFactory.BuildRightsRelationService();
            //调用实例方法
            return rightsRelationService.DeleteRightsRelationByOperatorId(operatorId);
        }

        /// 
        /// 修改单个权限关系
        /// 
        /// 权限关系实体
        /// True:成功/False:失败
        public bool ModifyRightsRelation(Model.RightsRelation rightsRelation)
        {
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();
            //调用工厂方法生成实例
            IDAL.IRightsRelationService rightsRelationService = absDALFactory.BuildRightsRelationService();
            //调用实例方法
            return rightsRelationService.ModifyRightsRelation(rightsRelation);
        }

        /// 
        /// 获取所有的权限关系集合
        /// 
        /// 权限关系集合
        public List GetAllRightsRelation()
        {
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();
            //调用工厂方法生成实例
            IDAL.IRightsRelationService rightsRelationService = absDALFactory.BuildRightsRelationService();
            //调用实例方法
            return rightsRelationService.GetAllRightsRelation();
        }

        /// 
        /// 根据操作员 ID 获取对应的所有权限关系
        /// 
        /// 操作员 ID
        /// 权限关系集合
        public List GetRightsRelationByOperatorId(int id)
        {
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();
            //调用工厂方法生成实例
            IDAL.IRightsRelationService rightsRelationService = absDALFactory.BuildRightsRelationService();
            //调用实例方法
            return rightsRelationService.GetRightsRelationByOperatorId(id);
        }

        /// 
        /// 根据权限组 ID 获取与此权限组相关的权限关系数量
        /// 
        /// 权限组 ID
        /// 权限关系数量
        public int GetRightsRelationCountByRightsGroupId(int id)
        {
            //定义并实例化抽象工厂类
            DALFactory.AbstractDALFactory absDALFactory = DALFactory.AbstractDALFactory.Instance();
            //调用工厂方法生成实例
            IDAL.IRightsRelationService rightsRelationService = absDALFactory.BuildRightsRelationService();
            //调用实例方法
            return rightsRelationService.GetRightsRelationCountByRightsGroupId(id);
        }
        #endregion
    }
}

 (三)界面表示层(由于界面操作逻辑的复杂度较高,在此仅列出部分难点代码)
 
 1、权限菜单数据管理类(RightsMenuDataManager)
 
 C#源码清单:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Model = CodingMouse.CMHotelManager.Model;

namespace CodingMouse.CMHotelManager.UI.Common
{

    /// 
    /// 权限菜单数据管理类
    /// 
    public class RightsMenuDataManager

    {

        #region Private Members

        ///
        /// 保存当前被管理的菜单对象
        ///
        MenuStrip _msMain = null;

        ///
        /// 保存当前权限项 ID
        ///
        int _rightsId = 0;

        #endregion

        #region Internal Properties

        ///
        /// 被管理的菜单对象
        ///
        internal MenuStrip MsMain
        {
            get { return _msMain; }
            set { _msMain = value; }
        }
        #endregion

        #region Private Methods

        /// 
        ///  使用递归法读取菜单权限子项
        /// 
        /// 要保存到的菜单根项权限集合
        /// 当前菜单权限相对根项
        /// 
        private Model.Rights GetMenuRightsChildrenItem(Dictionary<string, Model.Rights> rightCollection, ToolStripMenuItem tsmiRootLevel)
        {
            // 显示下级菜单项元素 Text
            Model.Rights secondRights = null;

            // 使用 ToolStripItem 基类遍历获取下级菜单项
            foreach (ToolStripItem tsmiNextLevel in tsmiRootLevel.DropDownItems)
            {
                // ID 号累加
                _rightsId++;

                // 显示下级菜单项元素 Text
                secondRights = new Model.Rights();
                secondRights.Id = _rightsId;
                secondRights.ModelName = tsmiNextLevel.Name;
                secondRights.RightsState = false;
                secondRights.ParentLevelRightsName = rightCollection[tsmiRootLevel.Name].ModelName;

                // 如果是菜单项而不是其它菜单项类型
                if (tsmiNextLevel is ToolStripMenuItem)
                {
                    secondRights.RightsCaption = tsmiNextLevel.Text;
                    // 添加当前项到集合
                    rightCollection.Add(secondRights.ModelName, secondRights);
                    // 使用递归添加所有次级子项到集合
                    GetMenuRightsChildrenItem(rightCollection, tsmiNextLevel as ToolStripMenuItem);
                }
                // 如果是分隔项而不是其它菜单项类型
                else if (tsmiNextLevel is ToolStripSeparator)
                {
                    secondRights.RightsCaption = "━━━━";
                    // 添加此菜单分隔项到集合
                    rightCollection.Add((tsmiNextLevel as ToolStripSeparator).Name, secondRights);
                }
            }
            return secondRights;
        }

        /// 
        /// 使用递归法加载菜单权限子项
        /// 
        /// 权限集合
        /// 当前菜单权限相对根项
        private void LoadMenuRightsChildrenItem(Dictionary<string, Model.Rights> rightCollection, ToolStripMenuItem tsmiRootLevel)
        {
            // 使用 ToolStripItem 基类遍历获取下级菜单项
            foreach (ToolStripItem tsmiNextLevel in tsmiRootLevel.DropDownItems)
            {
                foreach (Model.Rights tmpRights in rightCollection.Values)
                {
                    // 如果是菜单项而不是其它菜单项类型
                    if (tsmiNextLevel is ToolStripMenuItem)
                    {
                        // 如果内部名称相同
                        if (tsmiNextLevel.Name == tmpRights.ModelName)
                        {
                            // 设置名称和显隐状态
                            tsmiNextLevel.Text = tmpRights.RightsCaption;
                            tsmiNextLevel.Visible = tmpRights.RightsState;

                            // 使用递归加载所有次级子项
                            LoadMenuRightsChildrenItem(rightCollection, tsmiNextLevel as ToolStripMenuItem);
                            break;
                        }
                    }
                    // 如果是分隔项而不是其它菜单项类型
                    else if (tsmiNextLevel is ToolStripSeparator)
                    {
                        // 如果内部名称相同
                        if (tsmiNextLevel.Name == tmpRights.ModelName)
                        {
                            // 设置显隐状态
                            tsmiNextLevel.Visible = tmpRights.RightsState;
                            break;
                        }
                    }
                }
            }
        }
        #endregion

        #region Internal Methods

        /// 
        /// 使用递归法读取菜单权限项
        /// 
        /// 要保存到的目标权限集合
        /// 权限集合
        internal Dictionary<string, Model.Rights> ReadMenuRightsItem(Dictionary<string, Model.Rights> rightCollection)
        {
            if (!(this.MsMain is MenuStrip))
                throw new Exception("未指定被管理的菜单对象!请使用本方法的另一重载指定菜单对象!");
            // 调用另一重载
            return this.ReadMenuRightsItem(this._msMain, rightCollection);
        }

        /// 
        /// 使用递归法读取菜单权限项
        /// 
        /// 当前被管理的菜单对象
        /// 要保存到的目标权限集合
        /// 权限集合
        internal Dictionary<string, Model.Rights> ReadMenuRightsItem(MenuStrip msCurrentMenu, Dictionary<string, Model.Rights> rightCollection)
        {
            // 遍历获取菜单根项
            foreach (ToolStripMenuItem tsmiRootLevel in msCurrentMenu.Items)
            {
                if (tsmiRootLevel is ToolStripMenuItem)
                {
                    // ID 号累加
                    _rightsId++;

                    // 显示菜单根项元素 Text
                    Model.Rights rootRights = new Model.Rights();
                    rootRights.Id = _rightsId;
                    rootRights.ModelName = tsmiRootLevel.Name;
                    rootRights.RightsCaption = tsmiRootLevel.Text;
                    rootRights.RightsState = false;
                    rootRights.ParentLevelRightsName = msCurrentMenu.Name;

                    // 如果未添加此权限则添加此权限到菜单根项的权限集合
                    bool isExist = false;
                    foreach (Model.Rights tmpRights in rightCollection.Values)
                    {
                        if (tmpRights.ModelName == rootRights.ModelName)
                            isExist = true;
                    }
                    if (!isExist)
                        rightCollection.Add(rootRights.ModelName, rootRights);

                    // 使用递归添加所有子项
                    GetMenuRightsChildrenItem(rightCollection, tsmiRootLevel);
                }
            }
            return rightCollection;
        }

        ///
        /// 使用递归法加载菜单权限项
        /// 要保存到的目标权限集合
        /// 权限集合
        internal void LoadMenuRightsItem(Dictionary<string, Model.Rights> rightCollection)
        {
            if (!(this.MsMain is MenuStrip))
                throw new Exception("未指定被管理的菜单对象!请使用本方法的另一重载指定菜单对象!");

            // 调用另一重载
            this.LoadMenuRightsItem(this._msMain, rightCollection);
        }

        /// 
        /// 使用递归法加载菜单权限项
        /// 
        /// 当前被管理的菜单对象
        ///  权限集合
        internal void LoadMenuRightsItem(MenuStrip msCurrentMenu, Dictionary<string, Model.Rights> rightCollection)
        {
            foreach (Model.Rights tmpRights in rightCollection.Values)
            {
                // 遍历获取菜单根项
                foreach (ToolStripMenuItem tsmiRootLevel in msCurrentMenu.Items)
                {
                    if (tsmiRootLevel is ToolStripMenuItem)
                    {
                        // 如果内部名称相同
                        if (tsmiRootLevel.Name == tmpRights.ModelName)
                        {
                            // 设置名称和显隐状态
                            tsmiRootLevel.Text = tmpRights.RightsCaption;
                            tsmiRootLevel.Visible = tmpRights.RightsState;

                            // 使用递归加载所有子项
                            LoadMenuRightsChildrenItem(rightCollection, tsmiRootLevel);
                            break;
                        }
                    }
                }
            }
        }
        #endregion
    }
}

 2、权限菜单界面管理类(RightsMenuUIManager)
 
 C#源码清单:

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using IBLL = CodingMouse.CMHotelManager.IBLL;
using BLLFactory = CodingMouse.CMHotelManager.BLLFactory;
using Model = CodingMouse.CMHotelManager.Model;

namespace CodingMouse.CMHotelManager.UI.Common
{
    /// 
    /// 权限菜单界面管理类
    /// 
    public class RightsMenuUIManager
    {
        #region Private Members
        DataGridView _dgvOperatorList = null;
        DataGridView _dgvRightsList = null;
        TreeView _tvRightsView = null;
        MenuStrip _msMain = null;
        Forms.frmRightsManager _rightsManagerUI = null;
        #endregion

        #region Internal Properties

        /// 
        /// 要操作的操作员列表 DataGridView 对象
        /// 
        internal DataGridView DgvOperatorList
        {
            get { return _dgvOperatorList; }
            set { _dgvOperatorList = value; }
        }

        /// 
        /// 要操作的权限列表 DataGridView 对象
        /// 
        internal DataGridView DgvRightsList
        {
            get { return _dgvRightsList; }
            set { _dgvRightsList = value; }
        }

        /// 
        /// 要操作的权限视图 TreeView 对象
        /// 
        internal TreeView TvRightsView
        {
            get { return _tvRightsView; }
            set { _tvRightsView = value; }
        }

        /// 
        ///  被管理的菜单对象
        /// 
        internal MenuStrip MsMain
        {
            get { return _msMain; }
            set { _msMain = value; }
        }

        /// 
        /// 当前被管理的操作界面
        /// 
        internal Forms.frmRightsManager RightsManagerUI
        {
            get { return _rightsManagerUI; }
            set { _rightsManagerUI = value; }
        }
        #endregion

        #region Private Methods

        /// 
        /// 加载所有树子节点
        /// 
        /// 当前子节点
        /// 所有权限集合
        /// 
        private TreeNode LoadAllChildTreeNode(TreeNode currentChildTreeNode, Dictionary<string, Model.Rights> rightsCollection)
        {
            // 如果是菜单分隔则设置突出显示
            if (currentChildTreeNode.Text == "━━━━")
            {
                currentChildTreeNode.ForeColor = Color.Red;
                currentChildTreeNode.ToolTipText = "<-- 菜单分隔 -->";
            }
            // 遍历同父权限项集合
            foreach (Model.Rights tmpRights in rightsCollection.Values)
            {
                // 如果当前父级权限项的权限名称与当前节点相同
                if (tmpRights.ParentLevelRightsName == currentChildTreeNode.Tag.ToString())
                {
                    // 为当前节点创建新的子节点
                    TreeNode newChildTreeNode = new TreeNode(tmpRights.RightsCaption);
                    newChildTreeNode.Tag = tmpRights.ModelName;
                    newChildTreeNode.Checked = tmpRights.RightsState;

                    // 创建同父权限项集合
                    List sameNessParentRightsList = new List();

                    // 获取所有与当前权限项具有相同父权限项的权限项
                    foreach (Model.Rights sameNessParentRights in rightsCollection.Values)
                    {
                        if (sameNessParentRights.ParentLevelRightsName == tmpRights.ParentLevelRightsName)
                            sameNessParentRightsList.Add(sameNessParentRights);
                    }
                    // 递归添加到当前节点及其所有子节点
                    currentChildTreeNode.Nodes.Add(LoadAllChildTreeNode(newChildTreeNode, rightsCollection));
                }
            }
            // 返回当前处理的节点
            return currentChildTreeNode;
        }
        #endregion

        #region Internal Methods

        /// 
        /// 将操作员集合数据绑定显示到数据视图
        /// 
        /// 操作员集合
        internal void BindOperatorInfoToDataGridView(Dictionary<string, Model.Operator> operatorCollection)
        {
            try
            {
                // 如果包含操作员信息
                if (operatorCollection.Count > 0)
                {
                    // 将权限集合绑定显示在数据视图中
                    BindingSource source = new BindingSource();
                    source.DataSource = operatorCollection.Values;
                    this._dgvOperatorList.DataSource = source;

                    // 设置中文列名及可写状态
                    this._dgvOperatorList.Columns["Id"].HeaderText = "编号";
                    this._dgvOperatorList.Columns["Id"].ToolTipText = "[只读列]";
                    this._dgvOperatorList.Columns["Id"].DisplayIndex = 0;
                    this._dgvOperatorList.Columns["Id"].ReadOnly = true;
                    this._dgvOperatorList.Columns["ModelName"].HeaderText = "操作员名称";
                    this._dgvOperatorList.Columns["ModelName"].ToolTipText = "[只读列]";
                    this._dgvOperatorList.Columns["ModelName"].DisplayIndex = 1;
                    this._dgvOperatorList.Columns["ModelName"].ReadOnly = true;
                    this._dgvOperatorList.Columns["Password"].HeaderText = "密码";
                    this._dgvOperatorList.Columns["Password"].DisplayIndex = 2;
                    this._dgvOperatorList.Columns["State"].HeaderText = "状态";
                    this._dgvOperatorList.Columns["State"].DisplayIndex = 3;
                    this._dgvOperatorList.Columns["RightsCollection"].HeaderText = "权限列表";
                    this._dgvOperatorList.Columns["RightsCollection"].DisplayIndex = 4;
                    this._dgvOperatorList.Columns["RightsCollection"].ReadOnly = true;
                    this._dgvOperatorList.Columns["RightsCollection"].Visible = false;

                    // 设置菜单分隔项的权限标题列为只读
                    foreach (DataGridViewRow dgvRow in this._dgvOperatorList.Rows)
                    {
                        // 设置单元格工具栏提示
                        foreach (DataGridViewCell dgvCell in dgvRow.Cells)
                        {
                            if (dgvCell.ReadOnly)
                                dgvCell.ToolTipText = "[只读格]";
                            else
                                dgvCell.ToolTipText = "[可写格]";
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(
                ex.Message,
                "加载失败",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error);
            }
        }

        /// 
        /// 将权限集合数据绑定显示到数据视图
        /// 
        /// 权限集合
        internal void BindDataToDataGridView(Dictionary<string, Model.Rights> rightsCollection)
        {
            try
            {
                // 保存所有选择单元格
                List<string> selectedCellValueList = new List<string>();
                foreach (DataGridViewCell dgvCell in _dgvRightsList.SelectedCells)
                {
                    selectedCellValueList.Add(dgvCell.Value.ToString().Trim());
                }

                // 将权限集合绑定显示在数据视图中
                BindingSource source = new BindingSource();
                source.DataSource = rightsCollection.Values;
                this._dgvRightsList.DataSource = source;

                // 设置中文列名及可写状态
                this._dgvRightsList.Columns["Id"].HeaderText = "编号";
                this._dgvRightsList.Columns["Id"].ToolTipText = "[只读列]";
                this._dgvRightsList.Columns["Id"].ReadOnly = true;
                this._dgvRightsList.Columns["Id"].DisplayIndex = 0;
                this._dgvRightsList.Columns["RightsCaption"].HeaderText = "权限标题";
                this._dgvRightsList.Columns["RightsCaption"].DisplayIndex = 1;
                this._dgvRightsList.Columns["ModelName"].HeaderText = "内部名称";
                this._dgvRightsList.Columns["ModelName"].ToolTipText = "[只读列]";
                this._dgvRightsList.Columns["ModelName"].ReadOnly = true;
                this._dgvRightsList.Columns["ModelName"].DisplayIndex = 2;
                this._dgvRightsList.Columns["RightsState"].HeaderText = "权限状态";
                this._dgvRightsList.Columns["RightsState"].DisplayIndex = 3;
                this._dgvRightsList.Columns["ParentLevelRightsName"].HeaderText = "父级权限";
                this._dgvRightsList.Columns["ParentLevelRightsName"].ToolTipText = "[只读列]";
                this._dgvRightsList.Columns["ParentLevelRightsName"].ReadOnly = true;
                this._dgvRightsList.Columns["ParentLevelRightsName"].DisplayIndex = 4;

                // 设置菜单分隔项的权限标题列为只读
                foreach (DataGridViewRow dgvRow in this._dgvRightsList.Rows)
                {
                    // 如果是菜单分隔项则设置为只读
                    if (dgvRow.Cells["RightsCaption"].Value.ToString().Trim() == "━━━━")
                        dgvRow.Cells["RightsCaption"].ReadOnly = true;

                    // 设置单元格工具栏提示
                    foreach (DataGridViewCell dgvCell in dgvRow.Cells)
                    {
                        if (dgvCell.ReadOnly)
                        {
                            dgvCell.ToolTipText = "[只读格]";
                            if (dgvCell.Value.ToString().Trim() == "━━━━")
                                dgvCell.ToolTipText += " | <-- 菜单分隔 -->";
                        }
                        else
                            dgvCell.ToolTipText = "[可写格]";
                    }
                }

                // 禁用关联选择
                RightsManagerUI.IsRelatingChooseCells = false;

                // 清除所有单元格选择
                _dgvRightsList.ClearSelection();

                // 还原原有选择
                foreach (string dgvSelectedCellValue in selectedCellValueList)
                {
                    foreach (DataGridViewRow dgvRow in _dgvRightsList.Rows)
                    {
                        foreach (DataGridViewCell dgvCell in dgvRow.Cells)
                        {
                            if (dgvCell.Value.ToString().Trim() == dgvSelectedCellValue)
                                dgvCell.Selected = true;
                        }
                    }
                }

                // 启用关联选择
                RightsManagerUI.IsRelatingChooseCells = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(
                ex.Message,
                "加载失败",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error);
            }
        }

        /// 
        /// 将数据绑定加载到树形视图
        /// 
        /// 权限集合
        internal void BindDataToTreeView(Dictionary<string, Model.Rights> rightsCollection)
        {
            // 禁用树视图的重绘
            _tvRightsView.BeginUpdate();

            // 清除原有节点
            _tvRightsView.Nodes.Clear();

            // 遍历权限集合以加载数据
            foreach (Model.Rights tmpRights in rightsCollection.Values)
            {
                // 定义权限根项
                TreeNode rootTreeNode = null;

                // 如果是权限根项
                if (tmpRights.ParentLevelRightsName == _msMain.Name)
                {
                    rootTreeNode = new TreeNode(tmpRights.RightsCaption);
                    rootTreeNode.Tag = tmpRights.ModelName;
                    rootTreeNode.Checked = tmpRights.RightsState;
                    _tvRightsView.Nodes.Add(rootTreeNode);
                }
                // 如果是权限子项
                else
                {
                    // 创建权限子项
                    TreeNode childTreeNode = new TreeNode(tmpRights.RightsCaption);
                    childTreeNode.Tag = tmpRights.ModelName;
                    childTreeNode.Checked = tmpRights.RightsState;

                    // 将子项添加到对应的父项中
                    foreach (TreeNode tmpTreeNode in _tvRightsView.Nodes)
                    {
                        // 如果与现存的节点父级权限相同
                        if (tmpTreeNode.Tag.ToString() == tmpRights.ParentLevelRightsName)
                        {
                            // 递归添加所有层级子节点
                            tmpTreeNode.Nodes.Add(LoadAllChildTreeNode(childTreeNode, rightsCollection));
                        }
                    }
                }
            }

            // 展开所有树节点
            _tvRightsView.ExpandAll();

            // 启用树视图的重绘
            _tvRightsView.EndUpdate();
        }

        /// 
        /// 选中/取消树节点及其子节点勾选状态
        /// 
        /// 当前操作的节点
        internal void CheckOrUnCheckTreeNode(TreeNode currentTreeNode)
        {
            // 如果有选中单元格
            if (_dgvOperatorList.SelectedCells.Count > 0)
            {
                // 保存当前选中行的操作员名称
                string operatorName = _dgvOperatorList.Rows[_dgvOperatorList.SelectedCells[0].RowIndex].Cells["ModelName"].Value.ToString().Trim();
                // 同步权限状态
                RightsManagerUI.OperatorCollection[operatorName].RightsCollection[currentTreeNode.Tag.ToString()].RightsState = currentTreeNode.Checked;

                // 同时选中/取消子节点的勾选
                foreach (TreeNode childTreeNode in currentTreeNode.Nodes)
                {
                    // 同步子节点勾选状态
                    childTreeNode.Checked = currentTreeNode.Checked;
                    // 递归勾选下层子节点
                    CheckOrUnCheckTreeNode(childTreeNode);
                }
            }
        }

        /// 
        /// 加载操作员列表
        /// 
        internal void LoadOperatorList()
        {
            BLLFactory.BLLFactory bllFactory = new BLLFactory.BLLFactory();
            IBLL.IOperatorManager operatorManager = bllFactory.BuildOperatorManager();
            // 加载操作员列表
            try
            {
                RightsManagerUI.OperatorCollection = operatorManager.GetAllOperatorInfo();
                // 检查所有操作员的权限列表
                foreach (Model.Operator tmpOperator in RightsManagerUI.OperatorCollection.Values)
                {
                    // 如果权限为空就创建一个新的空权限集合
                    if (!(tmpOperator.RightsCollection is Dictionary<string, Model.Rights>))
                    {
                        tmpOperator.RightsCollection = new Dictionary<string, Model.Rights>();
                        // 创建权限管理类实例
                        Common.RightsMenuDataManager rmdManager = new Common.RightsMenuDataManager();
                        // 创建权限集合空结构
                        tmpOperator.RightsCollection = rmdManager.ReadMenuRightsItem(_msMain, tmpOperator.RightsCollection);
                    }
                }
                // 如果包含操作员信息
                if (RightsManagerUI.OperatorCollection.Count > 0)
                {
                    // 将操作员集合数据绑定显示到数据视图
                    BindOperatorInfoToDataGridView(RightsManagerUI.OperatorCollection);
                    // 重新指定当前登录操作员对象
                    foreach (Model.Operator tmpOperator in RightsManagerUI.OperatorCollection.Values)
                    {
                        if (tmpOperator.ModelName == RightsManagerUI.CurrentOperator.ModelName)
                        {
                            RightsManagerUI.CurrentOperator = RightsManagerUI.OperatorCollection[RightsManagerUI.CurrentOperator.ModelName];
                            // 将数据绑定显示到数据视图
                            BindDataToDataGridView(RightsManagerUI.CurrentOperator.RightsCollection);
                            // 将数据绑定加载到树形视图
                            BindDataToTreeView(RightsManagerUI.CurrentOperator.RightsCollection);

                            // 在操作员列表中选中当前操作员
                            foreach (DataGridViewRow dgvRow in _dgvOperatorList.Rows)
                            {
                                if (dgvRow.Cells["ModelName"].Value.ToString().Trim() == RightsManagerUI.CurrentOperator.ModelName)
                                {
                                    dgvRow.Selected = true;
                                    break;
                                }
                            }
                            break;
                        }
                    }
                }
                else
                {
                    // 清空操作员列表的数据行
                    DgvOperatorList.Rows.Clear();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(
                ex.Message,
                "加载失败",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error);
            }
        }
        #endregion
    }
}
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

四、文章结语

 以上内容并未提供完整的源代码演示,仅仅提供一种解决此类问题的思路和方法。
 
 (一)技术难点
 
 1、将集合对象存储到数据库中(先使用序列化将集合对象流化,再将其转换为 Byte[] 数组);
 2、使用递归法解析菜单对象及应用权限菜单项的权限设置(注意 MenuStrip 对象的第一层级的子项集合为 Items ,其余均为 DropDownItems ,所以在递归解析或应用设置时只能从第二层级的子项开始进行递归调用);
 3、BindingSource 界面数据绑定对象 与 DataGridView 数据视图控件的配合使用(注意在绑定 Dictionary 泛型集合内容时,应直接将 BindingSource 的 DataSource 属性设置为该集合的 .Values 才能绑定到实际的内容);
 4、TreeView 树形视图控件的使用(注意在增删树节点时应适当使用 BeginUpdate() 和 EndUpdate() 方法来防止闪屏问题);
 5、隶属于多个权限组的操作员权限应为其所从属的多个权限组权限的并集(不算难,遍历一下集合即可)。

 (二)扩展思考
 
 此外,我所阐述的这种解决方案还可以再扩展一些人性化的功能。譬如本文没提及的一些人性化功能:
 
 1、让管理员用户完全自定义各个操作员的权限菜单标题(我已在自己的项目扩展此功能);
 2、让权限菜单项在禁用时同时将该项的 Enabled 属性设置为 False ,以防止被隐藏的菜单项被快捷键呼出(太简单了,读者自己在上面的代码中添加少量代码即可实现)。
 3、让管理员自由选择使用基于用户或基于角色的权限管理方案(由于在操作员和权限组两个实体模型中都各自存储了自身的权限集合,所以,在这种相对松散的权限关系下,很容易实现此功能,此功能我也已在自己的项目中实现)。

你可能感兴趣的:(C#)