EXTJS4.1MVC單表維護

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
            }   
        });
    }

});




發佈了16 篇原創文章 · 獲贊 0 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章