用户/密码:test1/test1 test2/test2 (注:同一用户在另一浏览器登录,另一用户在session失效后会被逼下线)
不少朋友下载源码后不怎么知道运行,请看这里补充的说明:
项目使用vs2010打开,数据使用sql server2005/2008
一、数据库创建与初始化数据
新建名为 Db_MDMS 的数据库
然后按顺序执行目录 Documents\MDMS.Documents\DB 1.0\Scripts 里的sql
1_tables.sql
2_functions.sql
3_stored-procedures.sql
4_init_data.sql
二、修改数据库连接信息
在目录 build\MSH 里修改 MSH.exe.config 的配置节点 MDMS.Db_ConnectionString 的值
三、
在vs2010中运行Web项目 MDMS.Web 或右键选择 default.aspx 页面点击在浏览器中浏览,然后打开目录 build\MSH ,双击MSH.exe运行之
这时,你可以用默认用户/密码 admin/admin888 登录系统了
写着写着,发现要整个系统都解说清楚太花时间了,大家有兴趣的话还是直接下载源码来看吧,个人觉得源码还算清晰,虽然没时间写注释:)
主数据管理问题存在的根源
对于大多数的企业都存在主数据管理的问题,个人以为这是由于业务发展的渐进性以及IT技术发展的渐进性造成的,正是由于这种渐进性,各大企业的业务系统从经历了从无到有,从简单到复杂,从而形成了一个又一个的业务竖井。从根本上来说,不可能只使用一个业务系统就能覆盖企业的所有业务,即便对一些国际大型的公司提供的套件来说也是一个不可能完成的任务(即便对套件来说,经常也存在一个跨国企业在不同的国家或地区部署多个实例的现象,也就是没有集中部署该套件,而是在很多地方分散部署了该套件)。对企业来说,业务系统的构建更多是以项目为中心,从下而上的构建系统,而不是至上而下的构建系统——这必然缺乏整个企业范围内的统一规划,从而使得一些需要在各个业务中共享的数据(主数据)被分散到了各个业务系统进行分别管理。由于分散管理的主数据不具备一致性、准确性、完整性,使得各个企业普遍存在着产品管理不力、供应商管理不力、订单管理不力等现象。解决这一问题的根本方法就是引入主数据管理(MDM),主数据不光指需要共享的数据,更包含需要共享的业务规则和策略。
一、主要功能需求
1.公司内部系统的管理,包括管理系统信息、系统权限定义、系统角色、系统角色拥有的权限等等。
2.统一的用户管理,包括管理用户信息、登录系统的限制、个人在各个系统的角色、个人在各个系统的永久与临时权限等等。
3.各系统的日志记录与查看。
4.服务器的管理。(说明一下,这里只是管理服务器的信息,数据是提供给一个专门管理服务器远程登录的子系统的)
...其它扩展需求(多语言目前不需要,但MTV框架已实现了)
二、主要界面展示
1.主界面
2.用户列表
3.个人登录限制
4.个人角色管理
5.个人永久权限
6.个人临时权限
7.系统列表
8.系统权限定义列表
9.添加权限项
10.系统角色管理
11.系统角色的权限
12.服务器管理
13.系统日志
三、数据表设计
LoginLimit : 用户在各个系统的登录限制
LoginState : 用户在各个系统的登录情况
OperationLog : 用户在各个系统的操作日志
PermissionGroup : 系统的权限定义分组
PermissionItem : 系统权限分组里的项
Role : 系统角色信息
Server : 服务器(组)信息
ServerParameter : 服务器参数信息
System : 系统信息
User :用户信息
UserPermission : 用户在各个系统的永久权限
UserRoleMapping : 用户在各个系统的角色关系
UserTempPermission : 用户在各个系统的临时权限
详细设计内容太多,请下载源码看里面的数据库设计文档。
三、系统架构说明
整个解决方案共20个项目,其中ProviderModules目录下的13个项目是应用WCF服务向业务层提供数据接口,这么做了为了以后把数据接口和网站开发分开来给团队独立管理维护。系统应用了N-tier架构的基本设计模式+WCF服务+MTV框架。其中WCF服务采用了KudySharp里的ModuleFramework,MTV框架也是集成在KudySharp里面的。下面对各个项目作简单的解说。
MDMS.Core项目是核心库,IProvider下是数据操作接口的定义,Models下是数据表实体模型类和其它扩展模型类,Modules下是应用ModuleFramework的相关类。DataProviderFactory用于根据配置产生实现数据接口的实例,而DataProviderManager则是管理这些实例的,下面请看代码:
(原先设计是把Data、IProvider、Models分别放在独立项目的,经典多层项目都这么干,但为了减少项目数,本人都放在MDMS.Core项目中了)
DataProviderFactory
///<summary>
///
///</summary>
internal static class DataProviderFactory
{
///<summary>
///
///</summary>
///<typeparam name="TProvider"></typeparam>
///<returns></returns>
public static TProvider Create<TProvider>()
{
TProvider provider;
Type interfaceType = typeof(TProvider);
string interfaceName = interfaceType.FullName;
string providerTypeName = string.Concat(MSHConfigs.MDMS_Db_Provider, ".", interfaceType.Name.Substring(1));
try
{
object instance = Assembly.Load(MSHConfigs.MDMS_Db_Provider).CreateInstance(providerTypeName);
provider = (TProvider)instance;
}
catch (Exception ex)
{
throw new Exception("Fail to create provider instance of " + providerTypeName, ex);
}
return provider;
}
}
DataProviderManager
///<summary>
///
///</summary>
public static class DataProviderManager
{
private static readonly ReadFreeCache<string, object> providerCache = ReadFreeCache<string, object>.Create(StringComparer.OrdinalIgnoreCase);
///<summary>
///
///</summary>
///<typeparam name="TIProvider"></typeparam>
///<returns></returns>
public static TProvider Get<TProvider>()
{
string interfaceName = typeof(TProvider).FullName;
object provider = providerCache.Get(interfaceName, key => DataProviderFactory.Create<TProvider>());
return (TProvider)provider;
}
}
MDMS.SqlServerProvider项目是数据接口sql server实现类库。里面用了KudySharp里的SqlServerHelper助手类,使数据操作更加简洁,请看下面的基类和用户表的数据接口实现类:
ProviderBase
///<summary>
/// 数据提供者基类
///</summary>
public abstract class ProviderBase
{
protected virtual string ConnectionString
{
get
{
return MSHConfigs.MDMS_Db_ConnectionString;
}
}
protected virtual object ExecuteNonQueryWithReturnValueParameter(string spName, params object[] parameterValues)
{
// 自动获取存储过程参数(第二次后会取被缓存的一个拷贝),并设置有返回值参数
SqlParameter[] parameters = SqlServerHelper.GetSpParameterSet(ConnectionString, spName, true, parameterValues);
// 执行存储过程
SqlServerHelper.ExecuteNonQuery(ConnectionString, CommandType.StoredProcedure, spName, parameters);
// 存储过程执行后的返回值
return parameters[0].Value;
}
protected virtual TModel GetModel<TModel>(Func<DataReader, TModel> getModel, string spName, params object[] parameterValues)
where TModel : new()
{
TModel entity = new TModel();
// 自动获取存储过程参数(第二次后会取被缓存的一个拷贝),并设置没有返回值参数
SqlParameter[] parameters = SqlServerHelper.GetSpParameterSet(ConnectionString, spName, false, parameterValues);
// 执行存储过程
using (var reader = SqlServerHelper.ExecuteReader(ConnectionString, CommandType.StoredProcedure, spName, parameters))
{
if (reader.Read())
{
// 读取数据
entity = getModel(reader);
}
}
return entity;
}
protected virtual List<TModel> GetModelList<TModel>(Func<DataReader, TModel> getModel, string spName, params object[] parameterValues)
where TModel : new()
{
List<TModel> list = new List<TModel>();
// 自动获取存储过程参数(第二次后会取被缓存的一个拷贝),并设置没有返回值参数
SqlParameter[] parameters = SqlServerHelper.GetSpParameterSet(ConnectionString, spName, false, parameterValues);
// 执行存储过程
using (var reader = SqlServerHelper.ExecuteReader(ConnectionString, CommandType.StoredProcedure, spName, parameters))
{
while (reader.Read())
{
// 读取数据
TModel entity = getModel(reader);
list.Add(entity);
}
}
return list;
}
public virtual PagedList<TModel> GetPagedList<TModel>(Func<DataReader, TModel> getModel, PagedSqlParameters pagedSqlParameters)
where TModel : new()
{
if (pagedSqlParameters.PageSize < 1 || pagedSqlParameters.PageSize > 50)
{
pagedSqlParameters.PageSize = 10;
}
// 执行存储过程(SqlServerHelper内置的分页存储过程)
using (var reader = SqlServerHelper.ExecutePagedReader(ConnectionString, pagedSqlParameters))
{
List<TModel> list = new List<TModel>();
while (reader.Read())
{
// 读取数据
TModel model = getModel(reader);
list.Add(model);
}
return list.ToPagedList(reader.PageSize, reader.PageIndex, reader.RecordCount);
}
}
}
UserProvider
///<summary>
/// 用户接口实现
///</summary>
public sealed class UserProvider : ProviderBase, IUserProvider
{
public bool Add(string userName, string password, string passwordSalt, UserGender gender, string realName, string email, string mobile, UserStatus status)
{
object value = ExecuteNonQueryWithReturnValueParameter("SP_MDMS_User_Add", userName, password, passwordSalt, gender, realName, email, mobile, status);
return (Convert.ToInt32(value) > 0);
}
public bool EditById(Guid id, string password, string passwordSalt, UserGender gender, string realName, string email, string mobile, UserStatus status)
{
object value = ExecuteNonQueryWithReturnValueParameter("SP_MDMS_User_EditById", id, password, passwordSalt, gender, realName, email, mobile, status);
return (Convert.ToInt32(value) > 0);
}
public bool EditPasswordByUserName(string userName, string password, string passwordSalt)
{
object value = ExecuteNonQueryWithReturnValueParameter("SP_MDMS_User_EditPasswordByUserName", userName, password, passwordSalt);
return (Convert.ToInt32(value) > 0);
}
public bool DeleteByIds(Guid[] ids)
{
object value = ExecuteNonQueryWithReturnValueParameter("SP_MDMS_User_DeleteByIds", SqlServerHelper.ToCommaString(ids));
return (Convert.ToInt32(value) > 0);
}
public bool SetStatusByIds(Guid[] ids, UserStatus status)
{
object value = ExecuteNonQueryWithReturnValueParameter("SP_MDMS_User_SetStatusByIds", SqlServerHelper.ToCommaString(ids), (byte)status);
return (Convert.ToInt32(value) > 0);
}
public UserModel GetById(Guid id)
{
return GetModel(GetUserModel, "SP_MDMS_User_GetById", id);
}
public UserModel GetByUserName(string userName)
{
return GetModel(GetUserModel, "SP_MDMS_User_GetByUserName", userName);
}
public PagedList<UserModel> GetPagedList(string userName, UserGender? gender, UserStatus? status, int pageSize, int pageIndex)
{
PagedSqlParameters sqlParameters = new PagedSqlParameters()
{
SelectExpression = "*",
FromExpression = "[dbo].[User]",
MasterTable = "[dbo].[User]",
MasterPrimaryKey = "[Id]",
AutoIncrementKeyMode = false,
WhereExpression = string.Empty,
OrderExpression = "[CreateDate]",
Descending = true,
MaxPageIndex = 0,
PageSize = pageSize,
PageIndex = pageIndex
};
if (!string.IsNullOrEmpty(userName))
{
sqlParameters.WhereExpression += " AND [UserName] LIKE '%" + SqlServerHelper.EscapeLike(userName) + "%'";
}
if (gender.HasValue)
{
sqlParameters.WhereExpression += " AND [Gender]=" + ((byte)gender.Value).ToString();
}
if (status.HasValue)
{
sqlParameters.WhereExpression += " AND [Status]=" + ((byte)status.Value).ToString();
}
return GetPagedList(GetUserModel, sqlParameters);
}
private UserModel GetUserModel(DataReader reader)
{
return new UserModel
{
Id = reader.GetGuid("Id"),
UserName = reader.GetString("UserName").Trim(),
Password = reader.GetString("Password"),
PasswordSalt = reader.GetString("PasswordSalt"),
Gender = (UserGender)reader.GetByte("Gender"),
RealName = reader.GetString("RealName").Trim(),
Email = reader.GetString("Email"),
Mobile = reader.GetString("Mobile").Trim(),
Status = (UserStatus)reader.GetByte("Status"),
CreateDate = reader.GetDateTime("CreateDate")
};
}
}
.....其它省略....
四、子系统怎么与主数据管理系统整合?
只要继承 MDMS.UserApiModule 项目里的ServiceContextBase类,就可以很轻松的实现用户的登录,退出,添加日志,读取权限等操作,其中主数据管理系统也作为了其中的一个子系统来管理了,可以参考此系统是怎么整合的,时间问题,不想再多写解说了。请谅解。
分享到:
相关推荐
与DotNet数据对象结合的自定义数据对象设计 (一) 数据对象与DataRow ASP.NET中大结果集的分页[翻译] .net 2.0 访问Oracle --与Sql Server的差异,注意事项,常见异常 Ado.net 与NHibernate的关系? 动态创建数据库...
本书共16章,分为4篇,详细讲解了使用各种软件和平台进行音、视频多媒体编程的技术,以案例为对象展示实现过程、分析技术难点。主要内容包括软件Visual C++2005的开发技术、DirectSound开发音频、DirectShow/VFW开发...
07 属主属组及基于数字的权限管理 第5章 01 上节课复习 02 文件合并与文件归档 03 文件归档与两种压缩方式 04 vim编辑器 05 系统启动流程 06 grub加密 07 bios加密 08 top命令 09 free命令 10 进程管理 第6章 01...
由于现有的手机应用程序的开发是构建在各手机厂家的私有操作系统之上的,所以它限制了第三方应用程序的开发,而Android为我们提供了一个开放和通用的选择。因为没有了人为制造的障碍,所以Android开发人员可以自由地...
关于本站“设计模式” Java 提供了丰富的 API,同时又有强大的数据库系统作底层支持,那么我们的编程似乎变成了类似积木的简单"拼凑"和调用, 甚至有人提倡"蓝领程序员",这些都是对现代编程技术的不了解所至. 在...
该案例既提供了ide无关的、基于ant管理的项目源码,也提供了基于netbeans ide的项目源码,最大限度地满足读者的需求。 作者简介: 李刚,从事10年的Java EE应用开发。曾任LITEON公司的J2EE技术主管,负责该公司的...
3、以ARCCIS9的功能结构主线,学习利用ARCCIS进行数据输入,数据编辑,地图配标,投影转换,数据转换,数据显示(包括三维显示)与制图,数据查询与分析,数据输出等一系列操作。(以ARCCIS在农业中的应为例介绍) ...
本书共16章,分为4篇,详细讲解了使用各种软件和平台进行音、视频多媒体编程的技术,以案例为对象展示实现过程、分析技术难点。主要内容包括软件Visual C++2005的开发技术、DirectSound开发音频、DirectShow/VFW开发...
本书共16章,分为4篇,详细讲解了使用各种软件和平台进行音、视频多媒体编程的技术,以案例为对象展示实现过程、分析技术难点。主要内容包括软件Visual C++2005的开发技术、DirectSound开发音频、DirectShow/VFW开发...
本书共16章,分为4篇,详细讲解了使用各种软件和平台进行音、视频多媒体编程的技术,以案例为对象展示实现过程、分析技术难点。主要内容包括软件Visual C++2005的开发技术、DirectSound开发音频、DirectShow/VFW开发...
本书共16章,分为4篇,详细讲解了使用各种软件和平台进行音、视频多媒体编程的技术,以案例为对象展示实现过程、分析技术难点。主要内容包括软件Visual C++2005的开发技术、DirectSound开发音频、DirectShow/VFW开发...
本书共16章,分为4篇,详细讲解了使用各种软件和平台进行音、视频多媒体编程的技术,以案例为对象展示实现过程、分析技术难点。主要内容包括软件Visual C++2005的开发技术、DirectSound开发音频、DirectShow/VFW开发...
本书共16章,分为4篇,详细讲解了使用各种软件和平台进行音、视频多媒体编程的技术,以案例为对象展示实现过程、分析技术难点。主要内容包括软件Visual C++2005的开发技术、DirectSound开发音频、DirectShow/VFW开发...
本书共16章,分为4篇,详细讲解了使用各种软件和平台进行音、视频多媒体编程的技术,以案例为对象展示实现过程、分析技术难点。主要内容包括软件Visual C++2005的开发技术、DirectSound开发音频、DirectShow/VFW开发...
本书共16章,分为4篇,详细讲解了使用各种软件和平台进行音、视频多媒体编程的技术,以案例为对象展示实现过程、分析技术难点。主要内容包括软件Visual C++2005的开发技术、DirectSound开发音频、DirectShow/VFW开发...
目前,电子系统设计广泛采用通用操作系统,达到降低系统的设计难度和缩短研发周期。实现操作 系统与硬件快速信息交换是电子系统设计的关键。 通用操作系统硬件驱动程序的开发,编写者不仅需要精通硬件设备、...
目前,电子系统设计广泛采用通用操作系统,达到降低系统的设计难度和缩短研发周期。实现操作系统与硬件快速信息交换是电子系统设计的关键。 通用操作系统硬件驱动程序的开发,编写者不仅需要精通硬件设备、...
第一次看到“逆向工程”这个词是在2001年的《机械工程学报》上的一篇文章中,主要是讲用三坐标测量仪测量产品中各个部件的三维尺寸并在计算机中快速建模、进而反推其设计思想和基本设计原则。第一次使用逆向工程工具...