一、引言
网站系统管理是网站系统设计的一个重要组成部分,通常说来系统管理包括用户管理、角色管理、模块管理和系统日志等功能。这些功能具有一定的通用性,一般网站应用中对这部分的需求基本一致。因此,对系统管理功能的设计具有一定的代表性。
本文讨论的网站系统管理功能采用微软的VS .NET 2005来实现,VS .NET 2005为开发者提供了丰富的控件和新的设计理念,是网络系统应用开发的有效工具,但目前VS .NET下关于系统设计框架结构的讨论较少,这方面的解决方案的实现方法还不是很多。为解决这一问题,笔者想从系统解决方案的框架入手,按MVC模式分层的思想来设计,在分析比较.NET各种解决方案的基础上,构建了一种通用性较好的三层企业级解决方案。为提高解决方案的实现效率,利用现有的代码生成工具完成一些重复性的编码工作,比较了目前流行的各种代码生成工具,发现CodeSmith的功能比较全面,其使用的语法与ASP.NET非常相似,便于开发者学习和使用,因此选择CodeSmith作为生成工具。在CodeSmith工具中已有很多可利用的代码模板,本系统的设计中借鉴NHibernate生成模板,并对它进行了改进。原来的模块只能根据数据库来生成NHibernate的映射文件和类文件,改进后可以生成模型层、领域层,页面层所有的文件,也包括了项目工程文件(*.sln文件和*.csproj文件),从而实现了由数据库到解决方案的代码自动生成功能。
笔者的设计是一种初步的尝试,希望能在软件设计模式的应用上进行一些研究,形成可操作的使用方法,以减少开发者的编程工作量,提高编程的效率,希望本文的方法能起到抛砖引玉的作用。
二、数据库设计
系统总体设计思路是自下而上的,根据系统的功能需求,先开始数据库设计,然后进行系统编码。本系统管理考虑的功能有部门管理、用户管理、角色管理、模块管理和系统日志等几个部分组成。系统共包括7张数据表,分别是用户信息表User、部门信息表Department、用户登录信息表UserLogin、角色信息表Roles、模块信息表Modules、用户角色关系表UserRole和角色模块关系表RoleModule,其数据关系如图1所示。数据库的设计还是基于用户的需求来考虑,首先建立了用户信息表,这是系统管理的基础,用户注册的信息存放于该表中。由于用户隶属于不同的部门,建立了部门信息表,这两者为一对多的数据关系,由于部门信息间也存在隶属关系,部门信息表自身也是一个一对多的数据关系表。系统通常是由若干功能模块组成,为实现对这些模块的管理功能,要定义一个模块信息表,记录模块的名称和页面地址等信息。为实现系统的权限分组管理,建立了角色信息表,它与模块信息表是多对多的数据关系,为方便设计,建立了角色与模块关系表,把这种多对多的数据关系转化为两个一对多的数据关系,以便于系统的设计。同样的道理,对用户与角色表的关系也一样,建立了用户角色关系表,形成两个一对多的数据关系。

图1 系统管理数据库结构图
三、系统实现
1.系统解决方案
系统解决方案由5个工程项目组成,其解决方案组成如图2所示。其中BOSS.Core, BOSS.Data和Web工程为主要项目,ProjectBase.Data和ProjectBase.Utils工程为引用的基础项目。其中ProjectBase.Data为数据访问基础类工程,提供了基础的数据访问接口和数据访问方法。ProjectBase.Utils为数据基础工具类,主要是为系统提供数据报错、警告等功能。这两个工程项目的目的是提供一个基础平台。设计的重点是在三个主要项目上,Web层为页面层,负责系统页面的显示。BOSS.Core层为领域层,负责系统的核心业务。BOSS.Data层为数据访问层,负责数据库访问有关的功能。其中BOSS.Core层的设计最为关键,它由三个文件夹组成,DataInterfaces文件夹为数据访问接口文件,Domain文件夹中为NHibernate的映射文件和类文件,Entity文件夹中为业务实体对象文件。按领域层的设计理念,避免“贫血模型”的设计,建立实体对象,让它具有基本的数据访问操作和业务管理的功能。

图2 系统解决方案组织图
这五个项目间存在一定的依赖关系,下面以用户表功能设计为例来说明它们之间的关系。
领域层BOSS.Core中对用户表功能的定义有三处。文件夹DataInterfaces中的IUserDao.cs定义访问接口如下,该接口利用泛型技术来实现了通用的数据访问接口,接口IDao的具体定义位于ProjectBase.Data层。
public interface IUserDao : IDao<User , int >
{
}
文件夹Domain中的User.cs定义如下,该类为模型类,类似于Java中的POJO文件,类DomainObject的具体定义位于BOSS.Core层。
public partial class User : DomainObject<int>
{
#region Member Variables
}
文件夹Domain中的映射文件User.hbm.xml定义如下所示,该文件为NHibernate的映射文件,这个与Hibernate中的使用方法基本一致。下面的代码说明了用户的主键标识为ID,它为整型,属性为数据库自动标识,另外,它有一个字符串的属性LoginName。
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="BOSS.Core.Domain.User, BOSS.Core" table="`User`" lazy="false">
<id name="ID" type="Int32" unsaved-value="null">
<column name="UserID" length="4" sql-type="int" not-null="true" unique="true" index="PK_User"/>
<generator class="native" /></id>
<property name="LoginName" type="String">
<column name="LoginName" length="50" sql-type="varchar" not-null="false"/>
</property>
Entity文件夹的类文件UserEntity.cs中定义,该文件目的是实现User类的业务逻辑功能。为解决模型层的“贫血”问题,在实体类中利用了.NET 2005中的部分类(partial class)的技术,对模型层的类在这里进行补充定义,加上系统的业务管理功能。
public partial class User
{
//Business Method
}
数据访问层BOSS.Data中对用户访问的定义如下,其中类AbstractNHibernateDao的具体定义位于ProjectBase.Data层。该类的实现原理与上面的IUserDao接口类似,利用泛型技术实现了通用的数据操作功能,具体的操作函数在抽象类AbstractNHibernateDao已经有了明确定义,包括基本的数据添加、修改和删除功能。
public class UserDao : AbstractNHibernateDao<User, int>, IUserDao
{
public UserDao(string sessionFactoryConfigPath) : base(sessionFactoryConfigPath) { }
}
为系统使用该类的数据访问功能,需要对其进行初始化,系统设计中对数据访问层采用了DAO方式,使用工厂模式来进行设计,在工厂类中定义如下:
public IUserDao GetUserDao()
{
return new UserDao(sessionFactoryConfigPath);
}// sessionFactoryConfigPath为类工厂的配置文件路径
Web层使用该类功能代码示例如下:
User entity = new User();//创建领域模型
Department parent = new Department();
parent.DepartmentDao = DaoFactory.GetDepartmentDao();
//依赖注入,体现IOC的思想, DaoFactory为DAO工厂类,具体配置在CASTLE会有说明
entity.UserDao = DaoFactory.GetUserDao();
entity.LoginName = dataLoginName.Text.Trim();
entity.Password = dataPassword.Text.Trim();
entity.ActualName = dataActualName.Text.Trim();
entity.Address = dataAddress.Text.Trim();
entity.MobilePhone = dataMobilePhone.Text.Trim();
entity.OfficePhone = dataOfficePhone.Text.Trim();
entity.PostNumber = dataPostNumber.Text.Trim();
entity.Department = parent.GetById(int.Parse(dataDepartmentID.SelectedValue),false);
entity.CreateTime = DateTime.Now;
entity.State = 0;
if (entity.Save() != null)
{
lbinfo.Text = "添加用户信息成功";
}
2.关键技术
系统主要应用了CodeSmith代码生成工具, NHibernate技术和Castle技术。在实现部门管理中,还使用AJAX技术来实现无页面刷新的部门树结构,在此,对AJAX技术不作深入的讨论,具体实现方法参考代码实例。
(1)CodeSmith代码生成工具
CodeSmith是一个基于模板的代码生成器免费软件,目前笔者使用的版本为4.0。在程序开发中使用它自动生成代码,避免大量的重复代码的编写。CodeSmith可以生成任何基于ASCII的编程语言代码,它的语法与ASP.NET几乎相同。如果熟悉ASP.NET ,那么应该会很快理解模板语法,并且模板语法支持C#、VB.NET和JScript.NET等语言。CodeSmith带有不少优秀的模板,包括所有.NET集合类型的模板以及生成存储过程的模板等,但它真正强大的功能在于允许用户创建和定制模板,只要你掌握了CodeSmith的语法,定制了合适的开发模板,你也许会难以相信自己能制造如此神奇的工具,这也是CodeSmith最受人推崇的地方。 CodeSmith提供强大的数据库支持功能,利用它可以方便地访问到数据库的表对象、表间关系及存储过程对象等,这为我们代码生成功能提供了很好的条件。
下面的代码说明如何来实现让用户选择要操作的数据库,并得到该数据库中的所有数据表对象。
private DatabaseSchema _sourceDatabase;
[Category("Database")]
[Description("Database that the mapping file should be based on.")]
public DatabaseSchema SourceDatabase {
get { return _sourceDatabase; }
set { _sourceDatabase = value; }
}
//上面的代码是定义一个数据库连接,这样,在模板生成后会提示用户要选择需要操作的数据库。
foreach(TableSchema sourceTable in SourceDatabase.Tables)
{
//遍历数据库中的所有的表对象
if (IsManyToManyTable(sourceTable))
{
//判断是否是多对多的表
}
(2)NHibernate技术
NHibernate是一个面向.Net环境的对象/关系数据库映射工具。它采用了对象/关系数据库映射(object/relational mapping (ORM))技术,用来把对象模型表示的对象映射到基于SQL的关系模型数据结构中去。本文中使用的版本为1.2,支持.NET 2.0框架。使用NHibernate包括以下几个步骤:
NHibernate的基本配置,首先在.NET下添加NHibernate的引用,然后修改它的配置文件,包括连接数据提供者、连接数据驱动类、连接数据方言、数据库字符串等,本文用到的配置文件NHibernate.config如下所示。
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory name="EPZLDB">
<property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string">
Data Source=ADMIN;Initial Catalog=XTGLDB;Connect Timeout=30;user id=sa;
pwd=</property>
<property name="connection.isolation">ReadCommitted</property>
<property name="default_schema">XTGLDB.dbo</property>
<!-- HBM Mapping Files -->
<mapping assembly="BOSS.Core" />
</session-factory>
</hibernate-configuration>
持久化的.Net类与映射XML文件的生成。持久化类文件类似于Java的POJO文件,XML则负责完成对象与数据库之间的映射功能。NHibernate提供了由XML文件生成持久化类和数据库结构等功能,目前还不支持由数据库生成XML文件,只能利用工具来完成自动生成的功能。代码生成器CodeSmith已提供了NHibernate的生成模板,该模板能由数据库直接生成这两种文件。
使用NHibernate的API来编程。利用NHibernate提供的数据访问功能,通常情况下为便于设计,将提供的数据访问功能建立基础类,在其他业务对象使用它时,再调用这些基础类函数,没必要对每个业务对象把这些功能都再写一次。使用泛型技术有效地实现Nhibernate访问接口的封装。
(3)Castle技术
Castle是针对.NET平台的一个开源项目,从数据访问框架ORM到IOC容器,再到Web层的MVC框架、AOP,基本包括了整个开发过程中的所有内容,为快速的构建企业级的应用程序提供了很好的服务。Windsor是Castle 的一个IOC容器。它构建于MicroKernel之上,功能非常之强大,能检测类并了解使用这些类时需要何种参数,检测类型和类型之间工作依赖性,并提供服务或者发生错误时提供预警的机制。使用Windsor的步骤如下:
第一步:注册一个Windsor容器。
public void Application_Start(object sender, EventArgs e) {
// Initialize log4net
XmlConfigurator.Configure();
// Create the Windsor Container for IoC.
windsorContainer = new WindsorContainer(new XmlInterpreter());
}
第二步:向容器中注册服务。所谓服务,就是指我们要用到的组件类的接口,其具体的配置文件CastleComponents.config如下所示。
<?xml version="1.0"?>
<configuration>
<components>
<component id="primaryDaoFactory"
type="BOSS.Data.NHibernateDaoFactory, BOSS.Data"
service="BOSS.Core.DataInterfaces.IDaoFactory, BOSS.Core">
<parameters>
<sessionFactoryConfigPath>F:\编程论文\工程文件\Web\Config\NHibernate.config</sessionFactoryConfigPath>
</parameters>
</component>
</components>
</configuration>
上面的代码完成BOSS.Data中的工厂类NHibernateDaoFactory的注册。
第三步:在页面层中使用该注册服务,代码如下:
public IDaoFactory DaoFactory {
get {
return (IDaoFactory) CustomHttpApplication.WindsorContainer[typeof(IDaoFactory)];
}
这样,调用页面基础类的DaoFactory属性就可以得到工厂类,可以在页面中直接利用它对所有的DAO数据访问类进行调用。
四、结语
本文分析了网站系统管理的业务需求,并以此作为实例,研究其解决方案的组成,形成基于MVC的框架设计结构。从数据库设计入手,利用CodeSmith自动生成了解决方案的分层框架结构,并在VS .NET 2005下按MVC模式进行了功能实现。本文涉及到目前.NET研究最新的技术和工具,形成了一种比较高效的开发模式,具有较好的操作性,大大提高了开发效率。
|