EXTJS4.1MVC单表维护
2014-03-01 22:16
218 查看
EXTJS4.1做的单表维护,在同一个gridpanel中完成CRUD操作,数据处理方面借鉴webbuildder和pb中的处理,由于是刚开始学习extjs,可能有不合理的地方,希望大家批评,指正,下面是界面的效果图,还有MVC的相关代码。
我的一点小感受:
1。EXTJS的grid中可以设置CRUD的相关api, 但是这样的话增加,删除,修改的操作是在不同的事务里面,这样不利于事务的控制,比如说我修改了一条记录,又增加了一条记录,然后保存,会出现修改保存成功而增加保存失败,界面上会让用户感觉混乱;
而且这种方式提交时默认提交当前表格中的数据,不会将原始记录一起提交,后台无法比对数据,比如有10个字段,由于用户不知道哪个字段修改了,只能通过主键把所有字段都修改了;
再比如说当前要修改的记录已经被另一个用户修改,而你此时修改的话是不应该保存成功的,但是你通过主键去修改肯定是可以保存成功的,会造成数据覆盖的的情况发生。
2.我的这种做法主要是借鉴了pb里面的处理方式,将所有的增删改查的数据统一搜集发送到后台,后台统一操作,将操作控制在一个事务里面,后台执行顺序:删除所有要删除的数据, 删除所有在修改的记录集里面主键发生改变的记录,更新要修改的所有记录, 插入新增的记录和主键发生改变的新纪录。
修改和删除根据原始记录来查询,一旦根据原始记录没有查询出来,说明这条记录在另一个地方被修改或者删除了,程序会主动抛出异常,回滚事务。
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中看到过,所以就借鉴过来。
view 层代码
我的一点小感受:
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 } }); } });
相关文章推荐
- Linux服务器维护的四大法宝
- java调用JDBC连接MySQL 以及MySQL日常维护的简单操
- 虫虫博客2009-如何把搜索引擎排名维护好
- linux新机维护开始——重头再来
- DB2 日常维护指南,第 2 部分
- 一些MongoDB集群维护使用方法
- 维护Active Directory
- 《SQL Server 管理与维护指南》章节目录
- 爱立信Redback SmartEdge 800常用维护指令
- 【平衡树】【NOI 2005】维护数列
- 使用SQL Server维护计划实现数据库定时自动备份
- poj3264 线段树维护最大值最小值
- 例行维护前,你的测试部门加班吗?
- 第十三章创建与维护表
- 我的Oracle 9i学习日志(18)-- 维护数据完整性.b
- 十一、维护和平安定社会环境
- 后继无人:Linux核心维护人员日渐苍老
- hdu5398(lct维护最大生成树)
- Exchange 2007 邮件服务器的维护 推荐
- 数据库SQL Server2012笔记(五)——维护数据的完整性——约束