上一篇文章说过,系统由数据层,业务层,服务层,数据契约层,WCF代理层,ExtJs代理层,展现层组成。现在我们一起探讨这些层之间的作用。
众所周知,主流的三层结构由数据库,业务层与展现层组成。我认为:SOA架构在三层的基础上添加服务层,数据契约层,WCF代理层。
现在一起探讨一下各层之间的作用吧!
基于SOA架构采用Extjs展现的权限系统之总体设计探讨
上一篇文章说过,系统由数据层,业务层,服务层,数据契约层,WCF代理层,ExtJs代理层,展现层组成。现在我们一起探讨这些层之间的作用。
众所周知,主流的三层结构由数据库,业务层与展现层组成。我认为:SOA架构在三层的基础上添加服务层,数据契约层,WCF代理层。
现在一起探讨一下各层之间的作用吧!
数据层:用于与数据库交互的层。提供简洁实用的数据库访问方法,如:添加,删除,更新,查找等等。我这里的数据层采用Linq技术,由Linq自动生成数据访问层,节省了不少开发时间哦。
业务层:用于支撑业务需求,该层一般要具备高度灵活性,可扩展性,可配置等。大部份情况下会提供相关的工具一起支撑业务需求。如:配置管理器。在设计此层的时候,要考虑重用,节省下次开发软件的成本。个人认为:这也是衡量软件开发人员水平的一个重要因素。
服务层:SOA架构下,该层是必不可少的。服务层的作用是:业务以服务的形式提供外部接口。使业务的访问方式与平台,技术无关。把握服务的粒度是相当重要的。比如:权限系统中包含用户,用户组,权限,模块和他们这间的分配等操作。大家认为,服务的粒度该如何把握。我这里先提供两种个人想法:1. 将整个权限系统作为一个服务;2.将权限系统的各个功能块分别成为服务。如:用户服务,用户组服务等。目前我采用的是第一种方式,如果大家有更好的想法,希望一起探讨哦。
数据契约层:服务是离不开契约的,就像鱼和水的故事。因为契约是发布服务的方式。没有了它外部对服务就不可见了。既然他们不能分离,为什么不将数据契约层与服务层合并在一起呢,你这不是棒打鸳鸯麻。我也是迫不得已呀,因为我要让服务的实现代码与公开的接口进行分离,这样我们就可以使实现细节安全一些,保护鱼儿哇。
WCF代理层:该是用在客户端,也是必不可少呢。一般通过添加服务引用即可自动生成。
ExtJs代理层:为什么要有ExtJS代理层呢?因为ExtJs在与WCF直接交互将会遇到很多问题。如:WCF与ExtJs通过JSON序列化后日期格式的冲突,树的JSON格式(ExtJS树有自己的固定格式),WCF获取ExtJs的参数等。最最关键的是:我不能为了使用ExtJs而使服务层变成只支持ExtJs的服务,这脱离了服务的本质。因此我加入的ExtJs代理层。解决服务与ExtJS交互的问题。
ExtJs展现层:当我在07年的时候第一次看到ExtJs时,是多么的兴奋与喜悦。这世上还有如何美妙的Web界面。着实让我激动了好几天。当时JS还是菜鸟的我,就凭的一股傻劲肯下了这块硬骨头。家谈唠叨完了,下面说正题,大家见谅哇。ExtJs展现层是提供给用户操作的,直接影响的用户体验。现在的部份客户,已经不仅仅只要求软件能满足由业务需要,而且还要美观,易用,最好能一见钟情哇。有人说ExtJs很庞大,速度慢,难维护等相关缺点。是的,我不否认这些观点,ExtJs并不是十全十美,但它也解决了很多问题。如:树。ASP.NET提供的树与ExtJs提供的树根本不在一个层次。记得有篇文章《为了树,也要学习ExtJs》。我现在为用户组分配用户等这类的功能,准备以拖放的形式进行分配,提高易用性及用户体验,使Web的应用程序也能拥有Winform的效果。如果大家有更易用的分配方式,请不吝赐教哦。关于ExtJs很庞大,我觉的ASP.NET更庞大。为什么不排斥呢?我觉得,它由容易调试,写代码方便等因素决定的。反之JS,难调试,写代码也没有像样的智能提示。关于速度慢, 200多K的文件下载,第一次的访问的速度确实快不到哪去。所以我推荐将ExtJs用于后台管理,前端访问量大的可以采用JQuery这些轻量极的工具。但ExtJs将很多事情放在客户端作,一定程度降低了服务端的压力。关于难维护这个缺点,我也谈谈个人的看法。如果将JS代码进行良好的组织,维护还是可以的。我目前的JS代码都采用了命名空间并以包含或继承的方式实现。如:用户界面。我先实现自己的EditorGridPanel,然后User继承于EditorGridPanel实现用户的界面。如果分配用户的功能需要用户的界面,直接new User()就可以获得用户界面。这样可扩展性,可维护性,可重用性不就提高了么。下面贴一下这块的代码。欢迎大家拍砖哇~~。
EditorGridPanel类
/// <reference path="~/extjs/adapter/ext/ext-base.js"/>
/// <reference path="~/extjs/ext-all-debug.js"/>
/**
* author: 许道松
* email: fjfuqingxds@163.com
* createDate: 2008-9-28
*/
// EditorGridPanel类
// ================================
//创建自定义Grid,并继承自 Ext.grid.EditorGridPanel
XDS.Platform.Grid.EditorGridPanel = Ext.extend(Ext.grid.EditorGridPanel, {
constructor: function(config) {
this.clicksToEdit = 1;
this.autoScroll = true;
Ext.applyIf(this, {
store: new XDS.Platform.Data.Store({
url: XDS.Platform.config.UrlUnion(this.url, XDS.Platform.config.SelectOperation),
id: this.dataKey,
fields: this.fields,
grid: this,
listeners: {
beforeload: function() {
this.help = new XDS.Platform.Help();
this.help.beforeload(this.grid);
},
load: function() {
this.help.completeload(this.grid);
}
}
})
});
Ext.applyIf(this, {
viewConfig: {
forceFit: true,
columnsText: '列',
sortAscText: '升序',
sortDescText: '降序'
},
bbar: new Ext.PagingToolbar({
pageSize: this.pageSize,
store: this.store,
displayInfo: true,
displayMsg: '总记录数{0} - {1} of {2}',
emptyMsg: "没有记录"
})
});
if (Ext.isArray(this.operate)) {
Ext.applyIf(this, { tbar: new XDS.Platform.Grid.GridToolBar(this) });
}
XDS.Platform.Grid.EditorGridPanel.superclass.constructor.call(this, config);
},
load: function() {
this.getStore().load({ params: { start: 0, limit: this.pageSize} });
}
});
User实现
/// <reference path="~/extjs/adapter/ext/ext-base.js"/>
/// <reference path="~/extjs/ext-all-debug.js"/>
/**
* author: 许道松
* email: fjfuqingxds@163.com
* createDate: 2008-9-28
*/
// 用户类
//=================================================
XDS.Security.User = Ext.extend(XDS.Platform.Grid.EditorGridPanel, {
autoExpandColumn: 'UserName',
url: XDS.Platform.config.UserUrl,
dataKey: 'UserName',
pageSize: XDS.Platform.config.PageSize,
fields: Ext.data.Record.create([
{ name: 'UserID' },
{ name: 'UserName' },
{ name: 'Email' },
{ name: 'IsApproved' },
{ name: 'IsLockedOut' },
{ name: 'CreationDate' },
{ name: 'LastLoginDate' },
{ name: 'LastActivityDate' },
{ name: 'LastPasswordChangedDate' },
{ name: 'LastLockoutDate' },
{ name: 'Comment' },
{ name: 'PasswordQuestion' }
]),
constructor: function(config) {
config = config || {};
Ext.applyIf(this, config);
this.operate = config.operate || ["add", "delete", "save", "refresh"];
var chkIsApproved = new Ext.grid.CheckColumn({
header: "是否审核",
tooltip: "是否审核",
dataIndex: 'IsApproved',
width: 60
});
var chkIsLockedOut = new Ext.grid.CheckColumn({
header: "是否锁定",
tooltip: "是否锁定",
dataIndex: 'IsLockedOut',
width: 60
});
this.sm = new Ext.grid.CheckboxSelectionModel();
this.cm = new Ext.grid.ColumnModel([new Ext.grid.RowNumberer(), this.sm, {
id: 'UserName',
header: '用户名',
dataIndex: 'UserName',
width: 50
}, {
id: "Email",
header: "电子邮件",
dataIndex: 'Email',
width: 150
}, {
id: "PasswordQuestion",
header: "密码问题",
dataIndex: 'PasswordQuestion',
width: 100
}, {
header: '创建时间',
dataIndex: 'CreationDate',
width: 100,
renderer: XDS.Platform.Help.renderDate
}, chkIsApproved, chkIsLockedOut, {
header: "最后登陆时间",
width: 100,
dataIndex: "LastLoginDate",
renderer: XDS.Platform.Help.renderDate
}, {
header: "最后活动时间",
width: 100,
dataIndex: "LastActivityDate",
renderer: XDS.Platform.Help.renderDate
}, {
header: "最后更改密码时间",
width: 110,
dataIndex: "LastPasswordChangedDate",
renderer: XDS.Platform.Help.renderDate
}, {
header: "最后锁定时间",
width: 100,
dataIndex: 'LastLockoutDate',
renderer: XDS.Platform.Help.renderDate
}, {
header: "注释",
width: 100,
dataIndex: 'Comment',
editor: new Ext.form.TextField({
allowBlank: true
})
}]);
this.cm.defaultSortable = true;
Ext.menu.RangeMenu.prototype.icons = {
gt: 'images/greater_then.png',
lt: 'images/less_then.png',
eq: 'images/equals.png'
};
Ext.grid.filter.StringFilter.prototype.icon = 'images/find.png';
Ext.grid.filter.BooleanFilter.prototype.displayText = {
yes: '是',
no: '否'
};
Ext.grid.filter.DateFilter.prototype.displayText = {
before: '前',
after: '后',
on: '中'
};
var filters = new Ext.grid.GridFilters({
filters: [
{ type: 'numeric', dataIndex: 'ProductID' },
{ type: 'string', dataIndex: 'UserName' },
{ type: 'string', dataIndex: 'Email' },
{ type: 'string', dataIndex: 'PasswordQuestion' },
{ type: 'date', dataIndex: 'CreateDate' },
{ type: 'date', dataIndex: 'LastLoginDate' },
{ type: 'date', dataIndex: 'LastActivityDate' },
{ type: 'date', dataIndex: 'LastPasswordChangedDate' },
{ type: 'date', dataIndex: 'LastLockoutDate' },
{ type: "boolean", dataIndex: 'IsApproved' },
{ type: "boolean", dataIndex: 'IsLockedOut' },
{ type: 'string', dataIndex: 'Comment' }
]
});
var data = [
['0', '谁是你最爱的儿'],
['1', '谁是你的另一半'],
['2', '你的爱好是什么'],
['3', '我最喜欢的歌']
];
this.addPanel = new Ext.FormPanel({
labelAlign: 'right',
windowTitle: '注册新用户',
frame: true,
labelWidth: 60,
width: 300,
height: 200,
bodyStyle: 'padding:5px 5px 0',
defaultType: 'textfield',
defaults: { width: 180, anchor: '95%' },
collapsed: false,
items: [{
fieldLabel: '用户名',
name: 'UserName',
allowBlank: false
}, {
fieldLabel: '密码',
name: 'Password',
inputType: 'password',
allowBlank: false
}, {
fieldLabel: '确认密码',
inputType: 'password',
vtype: 'password',
initialPassField: 'reg_Password',
allowBlank: false
}, {
fieldLabel: '电子邮件',
name: 'Email',
vtype: 'email'
}, {
fieldLabel: '安全问题',
xtype: 'combo',
allowBlank: false,
store: data,
emptyText: '请选择安全问题',
name: 'Question'
}, {
fieldLabel: '安全答案',
name: 'Answer',
allowBlank: false
}]
});
this.plugins = [chkIsApproved, chkIsLockedOut, filters];
XDS.Security.User.superclass.constructor.call(this);
}
});