您的位置:首页 > Web前端 > JavaScript

EXTJS4.1MVC单表维护

2014-03-01 22:16 218 查看
EXTJS4.1做的单表维护,在同一个gridpanel中完成CRUD操作,数据处理方面借鉴webbuildder和pb中的处理,由于是刚开始学习extjs,可能有不合理的地方,希望大家批评,指正,下面是界面的效果图,还有MVC的相关代码。

我的一点小感受:

1。EXTJS的grid中可以设置CRUD的相关api, 但是这样的话增加,删除,修改的操作是在不同的事务里面,这样不利于事务的控制,比如说我修改了一条记录,又增加了一条记录,然后保存,会出现修改保存成功而增加保存失败,界面上会让用户感觉混乱;

而且这种方式提交时默认提交当前表格中的数据,不会将原始记录一起提交,后台无法比对数据,比如有10个字段,由于用户不知道哪个字段修改了,只能通过主键把所有字段都修改了;

再比如说当前要修改的记录已经被另一个用户修改,而你此时修改的话是不应该保存成功的,但是你通过主键去修改肯定是可以保存成功的,会造成数据覆盖的的情况发生。

2.我的这种做法主要是借鉴了pb里面的处理方式,将所有的增删改查的数据统一搜集发送到后台,后台统一操作,将操作控制在一个事务里面,后台执行顺序:删除所有要删除的数据, 删除所有在修改的记录集里面主键发生改变的记录,更新要修改的所有记录, 插入新增的记录和主键发生改变的新纪录。

修改和删除根据原始记录来查询,一旦根据原始记录没有查询出来,说明这条记录在另一个地方被修改或者删除了,程序会主动抛出异常,回滚事务。

@Override
public void saveOrgsByAll(List<Org> newDatasList,
List<Org> deleteDatasList, List<Org> modifyDatasList)
throws Exception {
/*
* 执行顺序为删除,修改,新增
*
*/
for (int i = 0; i < deleteDatasList.size(); i++) {
int deleteResult;
Org org = null;
org = deleteDatasList.get(i);
deleteResult = orgDao.deleteOrgByAll(org);
if (deleteResult == 0) {
throw new DeleteException();
}
}

//主键冲突时先删除原始记录
for (int i = 0; i < modifyDatasList.size(); i++) {
int deleteResult;
Org org = null;
org = modifyDatasList.get(i);

if ( ! org.getHospcode().equals(org.getOrigin().getHospcode())     ) {

deleteResult = orgDao.deleteOrgByAll(org.getOrigin());
if (deleteResult == 0) {
throw new DeleteException();
}

}

}

for (int i = 0; i < newDatasList.size(); i++) {
int andResult;
Org org = null;
org = newDatasList.get(i);
andResult = orgDao.insertOrg(org);
if (andResult == 0) {
throw new InsertException();
}
}

for (int i = 0; i < modifyDatasList.size(); i++) {
int updateResult;
int addResult;
Org org = null;
org = modifyDatasList.get(i);

if ( ! org.getHospcode().equals(org.getOrigin().getHospcode())    ) {

//主键冲突时先删除再插入,删除操作放在前面统一删除,避免主键发生冲突
addResult = orgDao.insertOrg(org);
if (addResult == 0) {
throw new InsertException();
}

} else {
updateResult = orgDao.updateOrgByAll(org);
if (updateResult == 0) {
throw new UpdateException();
}
}

}

}

<update id="updateRoleByAll" parameterType="com.sesan.slis.core.model.Role" >
update  af_role
<set>
<if test="roleId != origin.roleId">
roleId = #{roleId, jdbcType=VARCHAR},
</if>
<if test="roleName != origin.roleName">
roleName = #{roleName, jdbcType=VARCHAR},
</if>
<if test="description != origin.description">
description = #{description, jdbcType=VARCHAR},
</if>
<if test="status != origin.status">
status = #{status,jdbcType=INTEGER}
</if>

</set>

<where>
<if test="origin.roleId !=null">
and roleId    =#{origin.roleId, jdbcType=VARCHAR}
</if>
<if test="origin.roleId ==null">
and roleId is null
</if>
<if test="origin.roleName !=null">
and roleName =#{origin.roleName, jdbcType=VARCHAR}
</if>
<if test="origin.roleName ==null">
and roleName is null
</if>
<if test="origin.description !=null">
and description   =#{origin.description, jdbcType=VARCHAR}
</if>
<if test="origin.description ==null">
and description   is null
</if>
<if test="origin.status !=null">
and status  =#{origin.status, jdbcType=VARCHAR}
</if>
<if test="origin.status ==null">
and status  is null
</if>
</where>


3.在这里很想给大家介绍pb里面数据处理的方式,觉得pb在数据处理方便做的非常好:

1.修改或者删除数据可以通过主键,也可以通过主键和可更新的列,也可以通过主键和修改的列。(我借鉴的是第二种,只要我刚开始查询出来的记录中有一列发生改变(可能被其他用户修改),就不给更新,在我读的很多代码里面大多是直接通过主键,这种做法是最简单但却是最不安全的)

2..当主键发生冲突时,可以通过先删除原始记录再插入新纪录,也可以直接更新。(如果直接更新的话有时会失败,比如两条记录中主键发生互换,无论先更新哪一条都不会成功)



4.在pb的数据窗口里面有4个内存缓冲区,它们是:

主缓冲区(PrimaryBuffer):界面上能看到的数据,可能被用户修改。

过滤缓冲区(FilterBuffer):存放从主缓冲区中过滤掉的数据。

删除缓冲区(DeleteBuffer):存放从主缓冲区中删除掉的数据。

原始缓冲区(OriginalBuffer):存放从数据库里检索到的原始数据。

此外数据窗口上有行和列的修改状态

NotModified!:行和列的值是最初从数据库中检索出的值,

DataModified!:行和列的值在最初检索后发生了改变。

New!:行是新行单并未赋值。

NewModified!:新行且某些列被赋值。

在 pb中正是有了缓冲区和标志位的存在,pb的后台才会很容易按照事先约定的方式(第3点提到的)来生成CRUD的sql语句了。

其实这些技术在EXTJS的gridpanel中有的地方也有实现,比如删除的数据可以通过store.getRemovedRecords( )来得到,数据修改了可以通过record.dirty()来判断。但是想获取原始数据却没有办法(也可能是我没有找到,如果有的话希望各位高手能指导一下),而且新行的标志位也没有,所以我在程序中是通过自己添加新行标志和保存原始数据来实现的,这个处理方式我在webbuilder中看到过,所以就借鉴过来。

 

store.load({
scope: store,
callback: function(records, operation, success) {
if (success==true){
this.each(function(b) {
b.__origin = Ext.apply({}, b.data);
b.__isNew = undefined
})
}
}
});




view 层代码

Ext.define('rm.view.OrgMngMainView', {
extend: 'Ext.panel.Panel',
alias: 'widget.OrgMngMainView',
requires: [
'Ext.ux.CheckColumn'
],

height: 471,
width: 591,
layout: {
type: 'border'
},
title: '组织机构维护',
closable: true,
border : false,

initComponent: function() {
var me = this;

Ext.applyIf(me, {
dockedItems: [
{
xtype: 'toolbar',
dock: 'top',
items: [{
xtype : 'button',
iconCls : 'icon-add',
text : '添加',
action : 'addAction'
},  {
xtype : 'tbseparator'
}, {
xtype : 'button',
iconCls : 'icon-delete',
text : '删除',
action : 'delAction'
}, {
xtype : 'button',
iconCls : 'icon-save',
text : '保存',
action : 'saveAction'
}  ,  {
xtype : 'tbseparator'
}, {
xtype : 'button',
iconCls : 'icon-refresh',
text : '刷新',
action : 'refreshAction'
}
]
}
],
items: [
{
xtype: 'gridpanel',
region: 'center',
margin: '1 1 1 1',
title: '组织机构维护',
columnLines: true,
store: 'OrgStore',
columns: [{
xtype: 'rownumberer',
text:'行号',
width:50

},{
xtype: 'gridcolumn',
dataIndex: 'hospcode',
text: '医院编码',
editor: {
xtype: 'textfield'
}
},{
xtype: 'gridcolumn',
dataIndex: 'hospname',
text: '医院名称',
width: 300,
editor: {
xtype: 'textfield'
}
},{

xtype: 'checkcolumn',
header: '启用',
dataIndex: 'status',
width: 60,
editor: {
xtype: 'checkbox',
cls: 'x-grid-checkheader-editor'
}

}
],

plugins: [
new Ext.grid.plugin.CellEditing({
clicksToEdit: 1
})
],
viewConfig: {
enableTextSelection: true
}
}
]
});

me.callParent(arguments);
}

});

Ext.define('rm.model.OrgModel', {
extend: 'Ext.data.Model',

requires: [
'Ext.data.Field'
],

fields: [
{
name: 'hospcode',
type: 'string'
},
{
name: 'hospname',
type: 'string'
},
{
name: 'status', type: 'boolean'
},
{
name:'text' ,
convert: function(value, record) {

return record.get("hospcode")+"|"+record.get("hospname");
}

}
]
});

Ext.define('rm.store.OrgStore', {
extend: 'Ext.data.Store',

requires: [
'rm.model.OrgModel',
'Ext.data.proxy.Ajax',
'Ext.data.reader.Json'
],

constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
model: 'rm.model.OrgModel',
storeId: 'OrgStore',
proxy: {
type: 'ajax',
url: 'org/getOrgs',
reader: {
type: 'json'
}
}
}, cfg)]);
}
});

Ext.define('rm.controller.OrgMainController', {
extend: 'Ext.app.Controller',

refs: [
{
ref: 'window',
selector: 'OrgMngMainView'
}
],

initWindow: function(component, eOpts) {
this.refresh();

},

refresh :function(  button, e, eOpts){
var window = this.getWindow();
var grid = window.down("gridpanel");
var store = grid.getStore();
store.load({
scope: store,
callback: function(records, operation, success) {
if (success==true){
this.each(function(b) {
b.__origin = Ext.apply({}, b.data);
b.__isNew = undefined
})
}
}
});
},
add:function(  button, e, eOpts){
var window = this.getWindow();
var grid =  window.down('gridpanel');
var store = grid.getStore();
var row ;
var record;
var edit = grid.plugins[0] ;
var gridsel = grid.getSelectionModel().getSelection( ) ;
if (gridsel.length>0){
row =store.indexOf( gridsel[0] );
}else{
row = 0;
}

store.insert(row,{ });
grid.getSelectionModel().select(row);//滚动到当前行
record=store.getAt(row);
record.__isNew=true;
record.commit();
edit.startEditByPosition({row:row,column:1});
},

delete:function(  button, e, eOpts){
var window = this.getWindow();
var grid =  window.down('gridpanel');
var store = grid.getStore();
var sels=    grid.getSelectionModel().getSelection( ) ;
var row;
var i;
if  (sels.length<=0){
return ;
}
store.remove(sels);
},
save :function(  button, e, eOpts){
var window = this.getWindow();
var grid =  window.down('gridpanel');
var store = grid.getStore();
var j = store.getCount();
var i;
var record;
var data;
var m=[],n=[],d=[];
var deleteRerords  ;
//获取新增或修改的记录
for(i=j-1;i>=0;i--){
record=store.getAt(i);
if(record.dirty){
data = Ext.apply({},record.data )
if(record.__isNew){
n.push(data);
}else{
data.origin=record.__origin;
m.push(data);
}
}else if( record.__isNew ){
store.remove(record);
}
}
//获取删除的记录
deleteRerords = store.getRemovedRecords( );
for(i=0 ;i<deleteRerords.length;i++){

if( !deleteRerords[i].__isNew ){
d.push(deleteRerords[i].__origin);

}

}

//ajax提交数据
Ext.Ajax.request({
scope: this,
url:   'org/saveOrgs',
params: {
newDatas:Ext.encode(n),
deleteDatas:Ext.encode(d),
modifyDatas:Ext.encode(m)
},
success : function(response, options){
this.refresh( );
}
});

},

init: function(application) {
this.control({

'OrgMngMainView button[action=addAction]' : {
click : this.add
},
'OrgMngMainView button[action=delAction]' : {
click : this.delete
},
'OrgMngMainView button[action=saveAction]' : {
click : this.save
},
'OrgMngMainView button[action=refreshAction]' : {
click : this.refresh
},
"OrgMngMainView": {
afterrender: this.initWindow
}
});
}

});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  CRUD 单表维护 EXTJS