本項目使用的開發環境及技術列舉以下:
一、開發環境
IDE:VS2010+MVC4
數據庫:SQLServer2008
二、技術
前端:Extjs
後端:
(1)、數據持久層:輕量級ORM框架PetaPoco
(2)、依賴注入:AutoFac
(3)、對象關係映射:AutoMapper
(4)、數據驗證(MVC自帶的驗證封裝使用)
(5)、SQL翻譯機
(6)、緩存html
以上使用都參考或直接借鑑使用了園子內牛人們的代碼,只是學習交流使用而已,還請勿怪,我爲了簡便,沒有分多個類庫,而是以文
件夾的形式分的,你們能夠根據文件夾分紅類庫也是同樣的。好了,廢話很少說,仍是先上幾張圖你們看看吧,若是有興趣再往下看前端
本項目雖然功能很少,可是基本已經涵蓋了extjs的全部基本用法了,對於通常的extjs初學者或是簡單應用的開發應該是足夠了,後
臺開發主要在tab、grid、treegrid的用法比較多,也是比較麻煩的地方,下面直接上代碼,你們看看web
首頁佈局:ajax
1 /** 2 * 程序主入口 3 */ 4 Ext.onReady(function () { 5 /** 6 * 上,panel.Panel 7 */ 8 this.topPanel = Ext.create('Ext.panel.Panel', { 9 region: 'north', 10 height: 55 11 }); 12 /** 13 * 左,panel.Panel 14 */ 15 this.leftPanel = Ext.create('Ext.panel.Panel', { 16 region: 'west', 17 title: '主菜單', 18 iconCls: 'House', 19 width: 200, 20 layout: 'accordion', 21 collapsible: true 22 }); 23 /** 24 * 右,tab.Panel 25 */ 26 this.rightPanel = Ext.create('Ext.tab.Panel', { 27 region: 'center', 28 layout: 'fit', 29 id: 'mainContent', 30 collapisble: true, 31 tabWidth: 120, 32 items: [{ title: '首頁', html: ' <iframe scrolling="auto" frameborder="0" width="100%" height="100%" src="' + DefaultUrl + '"> </iframe>'}] 33 }); 34 /** 35 * 下,panel.Panel 36 */ 37 this.bottomPanel = Ext.create('Ext.panel.Panel', { 38 region: 'south', 39 layout: 'fit', 40 id: 'foot', 41 collapisble: true, 42 height: 30, 43 html:'<div>歡迎您光臨!</div>' 44 }); 45 /** 46 * 組建樹 47 */ 48 Ext.define('TreeModelExtension', { 49 extend: 'Ext.data.Model', 50 //當Model實體類模型被用在某個TreeStore上,而且第一次實例化的時候 ,這些個屬性會添加到Model實體類的的原型(prototype )上 (至於上述代碼,則是經過把他設置爲根節點的時候觸發實例化處理的) 51 fields: [ 52 {name: 'text', type: 'string'}, 53 {name: 'url', type: 'string'} 54 ], 55 }); 56 var buildTree = function (json) { 57 return Ext.create('Ext.tree.Panel', { 58 rootVisible: false, 59 border: false, 60 store: Ext.create('Ext.data.TreeStore', { 61 model:'TreeModelExtension', 62 root: { 63 expanded: true, 64 children: json.children 65 } 66 }), 67 listeners: { 68 'itemdblclick': function (view, record, item, 69 index, e) { 70 var id = record.get('id'); 71 var text = record.get('text'); 72 var iconCls = record.get('iconCls'); 73 var leaf = record.get('leaf'); 74 var url = record.get('url'); 75 if (leaf) { //沒有子節點時才建立新的tab顯示 76 var tabs = Ext.getCmp('mainContent'); //獲取佈局頁的Tab組件 77 var Loadtab = Ext.getCmp(id); //判斷Tab是否已經加載 78 if(Loadtab==undefined){ //未加載則加載 79 tabs.add({ 80 id:id, 81 closable: true, 82 //這種方式採起了加載多個iframe的方式,優化看如何採起一個iframe的方式 83 html: ' <iframe scrolling="auto" frameborder="0" width="100%" height="100%" src="' + url + '"> </iframe>', 84 iconCls: iconCls, 85 title: text 86 }).show() 87 }else{ //已加載則設置爲活動頁 88 //tabs.setActiveTab(id); //適合於數據量較大,可是不須要實時改變得狀況下,直接將已打開的tab設置爲活動tab 89 90 //適合於須要實時展現最新數據的狀況,先移除已打開的此tab,而後再從新加載 91 tabs.remove(id); 92 tabs.add({ 93 id: id, 94 closable: true, 95 //這種方式採起了加載多個iframe的方式,優化看如何採起一個iframe的方式 96 html: ' <iframe scrolling="auto" frameborder="0" width="100%" height="100%" src="' + url + '"> </iframe>', 97 iconCls: iconCls, 98 title: text 99 }).show() 100 } 101 } 102 }, 103 scope: this 104 } 105 }); 106 }; 107 /** 108 * 加載菜單樹 109 */ 110 Ext.Ajax.request({ 111 url: AjaxPath, 112 113 success: function (response) { 114 var json = Ext.JSON.decode(response.responseText) 115 Ext.each(json.data, function (el) { 116 var panel = Ext.create( 117 'Ext.panel.Panel', { 118 id: el.id, 119 title: el.text, 120 iconCls:el.iconCls, 121 layout: 'fit' 122 }); 123 panel.add(buildTree(el)); 124 leftPanel.add(panel); 125 }); 126 }, 127 failure: function (request) { 128 Ext.MessageBox.show({ 129 title: '操做提示', 130 msg: "鏈接服務器失敗", 131 buttons: Ext.MessageBox.OK, 132 icon: Ext.MessageBox.ERROR 133 }); 134 }, 135 method: 'post' 136 }); 137 /** 138 * Viewport 139 */ 140 Ext.create('Ext.container.Viewport', { 141 layout: 'border', 142 renderTo: Ext.getBody(), 143 items: [this.topPanel, this.leftPanel, this.rightPanel, this.bottomPanel] 144 }); 145 });
Grid行內增刪改查:sql
1 Ext.onReady(function () { 2 // ExtJS組件自適應瀏覽器大小改變,看還有沒有其餘實現方式 3 Ext.EventManager.onWindowResize(function () { 4 Ext.ComponentManager.each(function (cmpId, cmp, length) { 5 if (cmp.hasOwnProperty("renderTo")) { 6 cmp.doLayout(); 7 } 8 }); 9 }); 10 var toolbar = Ext.create('Ext.toolbar.Toolbar', { 11 renderTo: document.body, 12 items: [ 13 // 使用右對齊容器 14 '->', // 等同 { xtype: 'tbfill' } 15 { 16 xtype: 'textfield', 17 name: 'roleName', 18 id: 'roleName', 19 emptyText: '輸入角色名關鍵字', 20 listeners: { 21 specialkey: function (field, e) { 22 if (e.getKey() == Ext.EventObject.ENTER) { 23 store.load({ //傳遞查詢條件參數 24 params: { 25 roleName: Ext.getCmp('roleName').getValue() 26 } 27 }); 28 } 29 } 30 } 31 }, 32 { 33 // xtype: 'button', // 默認的工具欄類型 34 text: '查詢', 35 tooltip: '根據數據條件查詢數據', 36 iconCls: "Zoom", 37 listeners: { 38 click: function () { 39 store.load({ //傳遞查詢條件參數 40 params: { 41 roleName: Ext.getCmp('roleName').getValue() 42 } 43 }); 44 } 45 } 46 }, 47 // 添加工具欄項之間的垂直分隔條 48 '-', // 等同 {xtype: 'tbseparator'} 建立 Ext.toolbar.Separator 49 { 50 // xtype: 'button', // 默認的工具欄類型 51 text: '重置', 52 tooltip: '清空當前查詢條件', 53 iconCls: "Arrowrotateanticlockwise", 54 handler: function () { //此事件能夠代替click事件 55 Ext.getCmp('roleName').setValue(""); 56 } 57 }, 58 ] 59 }); 60 //1.定義Model 61 Ext.define("BeiDream.model.BeiDream_Role", { 62 extend: "Ext.data.Model", 63 fields: [ 64 { name: 'ID', type: 'int' }, 65 { name: 'Name', type: 'string' }, 66 { name: 'Description', type: 'string' }, 67 { name: 'IsUsed', type: 'boolean', defaultValue: true } 68 ] 69 }); 70 //2.建立store 71 var store = Ext.create("Ext.data.Store", { 72 model: "BeiDream.model.BeiDream_Role", 73 autoLoad: true, 74 pageSize: 10, 75 proxy: { 76 type: 'ajax', 77 api: { 78 read: RoleListUrl, //查詢 79 create: AddUrl, //建立 80 update: UpdateUrl, //更新,必須真正修改了纔會觸發 81 destroy: RemoveUrl //刪除 82 }, 83 reader: { 84 type: 'json', 85 root: 'data' 86 }, 87 writer: { 88 type: 'json', //默認格式 //MVC下後臺使用模型自動進行轉換,若是是普通webform,則配置root:'data',encode:'true',這樣以後就可使用request【data】獲取 89 writeAllFields: true, //false只提交修改過的字段 90 allowSingle: false //默認爲true,爲true時,一條數據不以數組形式提交,爲false時,都以數組形式提交,這樣避免了提交了一條數據時,後臺是list模型沒法接收到數據問題 91 }, 92 listeners: { 93 exception: function (proxy, response, operation) { 94 grid.store.load(); //刪除失敗,數據從新加載 95 var resText = Ext.decode(response.responseText); 96 Ext.MessageBox.show({ 97 title: '服務器端異常', 98 msg: resText.msg, 99 icon: Ext.MessageBox.ERROR, 100 buttons: Ext.Msg.OK 101 }); 102 } 103 } 104 } 105 // sorters: [{ 106 // //排序字段。 107 // property: 'id' 108 // }] 109 }); 110 store.on('beforeload', function (store, options) { 111 var params = { roleName: Ext.getCmp('roleName').getValue() }; 112 Ext.apply(store.proxy.extraParams, params); 113 }); 114 var Gridtoolbar = Ext.create('Ext.toolbar.Toolbar', { 115 renderTo: document.body, 116 items: [{ 117 text: '新增', 118 tooltip: '新增一條數據', 119 iconCls: 'Add', 120 handler: function () { 121 RowEditing.cancelEdit(); 122 // Create a model instance 123 var r = new BeiDream.model.BeiDream_Role(); 124 Ext.getCmp('RoleGrid').getStore().insert(0, r); 125 RowEditing.startEdit(0, 0); 126 } 127 }, '-', { 128 text: '編輯', 129 tooltip: '編輯當前選擇行數據', 130 iconCls: 'Pencil', 131 handler: function () { 132 RowEditing.cancelEdit(); 133 var data = Ext.getCmp("RoleGrid").getSelectionModel().getSelection(); 134 RowEditing.startEdit(data[0].index, 0); 135 }, 136 disabled: true 137 }, '-', { 138 itemId: 'removeUser', 139 text: '刪除', 140 tooltip: '能夠多選刪除多條數據', 141 iconCls: 'Delete', 142 handler: function () { 143 Ext.MessageBox.confirm('提示', '肯定刪除該記錄?', function (btn) { 144 if (btn != 'yes') { 145 return; 146 } 147 var sm = Ext.getCmp('RoleGrid').getSelectionModel(); 148 RowEditing.cancelEdit(); 149 150 var store = Ext.getCmp('RoleGrid').getStore(); 151 store.remove(sm.getSelection()); 152 store.sync(); //根據狀態執行對應的服務器方法,delete,放在remove後才能成功執行服務器方法 153 if (store.getCount() > 0) { 154 sm.select(0); 155 } 156 }); 157 }, 158 disabled: true 159 }, '-', { 160 itemId: 'gridSync', 161 text: '保存', 162 tooltip: '保存到服務器', 163 iconCls: 'Disk', 164 handler: function () { 165 grid.store.sync(); 166 grid.store.commitChanges(); //執行commitChanges()提交數據修改。 167 } 168 }, '-', { 169 itemId: 'gridCancel', 170 text: '取消', 171 tooltip: '取消全部的已編輯數據', 172 iconCls: 'Decline', 173 handler: function () { 174 Ext.MessageBox.confirm('提示', '肯定取消已編輯數據嗎?', function (btn) { 175 if (btn != 'yes') { 176 return; 177 } 178 grid.store.rejectChanges(); //執行rejectChanges()撤銷全部修改,將修改過的record恢復到原來的狀態 179 }); 180 } 181 }, '-', { 182 itemId: 'gridrefresh', 183 text: '刷新', 184 tooltip: '從新加載數據', 185 iconCls: 'Arrowrefresh', 186 handler: function () { 187 grid.store.load(); 188 } 189 }, '->', { 190 itemId: 'ImportExcel', 191 text: '導入Excel', 192 tooltip: '導入角色數據', 193 iconCls: 'Pageexcel', 194 handler: function () { 195 Ext.MessageBox.show({ 196 title: '暫未開放', 197 msg: '即將開放', 198 icon: Ext.MessageBox.ERROR, 199 buttons: Ext.Msg.OK 200 }); 201 } 202 }, '-', { 203 itemId: 'ExportExcel', 204 text: '導出Ecxel', 205 tooltip: '角色數據導出Excel', 206 iconCls: 'Pageexcel', 207 handler: function () { 208 Ext.MessageBox.show({ 209 title: '暫未開放', 210 msg: '即將開放', 211 icon: Ext.MessageBox.ERROR, 212 buttons: Ext.Msg.OK 213 }); 214 } 215 } 216 ] 217 }); 218 var RowEditing = Ext.create('Ext.grid.plugin.RowEditing', { // 行編輯模式 219 clicksToEdit: 2, //雙擊進行修改 1-單擊 2-雙擊 220 autoCancel: false, 221 saveBtnText: '肯定', 222 cancelBtnText: '取消', 223 errorsText: '錯誤', 224 dirtyText: '你要確認或取消更改', 225 listeners: { 226 cancelEdit: function (rowEditing, context) { 227 // Canceling editing of a locally added, unsaved record: remove it 228 if (context.record.phantom) { //服務器上是否有此條記錄的標誌,true爲沒有 229 store.remove(context.record); 230 } 231 }, 232 Edit: function (rowEditing, context) { 233 //store.sync(); //根據狀態執行對應的服務器方法,Add/Edit 234 var IsValidate = ValidateInput(context.record.data, context.record.phantom); 235 if (!IsValidate) { 236 grid.store.rejectChanges(); 237 } 238 }, 239 validateedit: function (rowEditing, context) { 240 241 } 242 } 243 }); 244 function ValidateInput(data, IsAdd) { 245 var IsValidate; 246 Ext.Ajax.request({ 247 url: ValidateInputUrl, 248 method: 'POST', 249 jsonData: data, 250 params: { IsAdd: IsAdd }, 251 async: false, 252 success: function (response) { 253 var resText = Ext.decode(response.responseText); 254 if (resText.success) { 255 Ext.MessageBox.alert('警告', resText.msg); 256 IsValidate = false; 257 } else { 258 IsValidate = true; 259 } 260 }, 261 failure: function (response, options) { 262 Ext.MessageBox.alert('服務器異常', response.status); 263 } 264 }); 265 return IsValidate; 266 } 267 //多選框變化 268 function selectchange() { 269 var count = this.getCount(); 270 //刪除 271 if (count == 0) { 272 Gridtoolbar.items.items[2].disable(); 273 Gridtoolbar.items.items[4].disable(); 274 } 275 else { 276 Gridtoolbar.items.items[2].enable(); 277 Gridtoolbar.items.items[4].enable(); 278 } 279 } 280 //3.建立grid 281 var grid = Ext.create("Ext.grid.Panel", { 282 id: "RoleGrid", 283 xtype: "grid", 284 store: store, 285 columnLines: true, 286 renderTo: Ext.getBody(), 287 selModel: { 288 injectCheckbox: 0, 289 listeners: { 290 'selectionchange': selectchange 291 }, 292 mode: "MULTI", //"SINGLE"/"SIMPLE"/"MULTI" 293 checkOnly: false //只能經過checkbox選擇 294 }, 295 selType: "checkboxmodel", 296 columns: [ 297 { xtype: "rownumberer", text: "序號", width: 40, align: 'center' }, 298 { id: "id", text: "ID", width: 40, dataIndex: 'ID', sortable: true, hidden: true }, 299 { text: '角色名稱', dataIndex: 'Name', flex: 1, editor: "textfield" }, 300 { text: '角色描述', dataIndex: 'Description', flex: 1, editor: "textfield" }, 301 { text: '是否啓用', dataIndex: 'IsUsed', flex: 1, xtype: 'checkcolumn', editor: { xtype: 'checkbox', cls: 'x-grid-checkheader-editor'} } 302 ], 303 plugins: [RowEditing], 304 listeners: { 305 itemdblclick: function (me, record, item, index, e, eOpts) { 306 //雙擊事件的操做 307 } 308 }, 309 tbar: Gridtoolbar, 310 bbar: { xtype: "pagingtoolbar", store: store, displayInfo: true, emptyMsg: "沒有記錄" } 311 }); 312 });
TreeGrid展現:前臺代碼和後臺模型結合數據庫
Ext.onReady(function () { // ExtJS組件自適應瀏覽器大小改變,看還有沒有其餘實現方式 Ext.EventManager.onWindowResize(function () { Ext.ComponentManager.each(function (cmpId, cmp, length) { if (cmp.hasOwnProperty("renderTo")) { cmp.doLayout(); } }); }); Ext.create('Ext.container.Viewport', { layout: 'border', renderTo: Ext.getBody(), items: [{ title: '主菜單模塊', region: 'west', xtype: 'panel', margins: '5 0 0 5', width: 200, collapsible: true, // 可摺疊/展開 id: 'NavigationMenucontainer', layout: 'fit' }, { title: '子菜單列表', region: 'center', // 必須指定中間區域 xtype: 'panel', layout: 'fit', id: 'Gridcontainer', margins: '5 5 0 0' }] }); var NavigationMenu=Ext.getCmp('NavigationMenucontainer'); /** * 加載菜單樹 */ Ext.Ajax.request({ url: AjaxPath, success: function (response) { var json = Ext.JSON.decode(response.responseText) Ext.each(json.data, function (el) { var panel = Ext.create( 'Ext.panel.Panel', { id: el.id, layout: 'fit' }); var ShowGrid=CreateGrid(el.id); Gridcontainer.add(ShowGrid); //初始化,加載主菜單下的菜單 panel.add(buildTree(el)); NavigationMenu.add(panel); }); }, failure: function (request) { Ext.MessageBox.show({ title: '操做提示', msg: "鏈接服務器失敗", buttons: Ext.MessageBox.OK, icon: Ext.MessageBox.ERROR }); }, method: 'post' }); var Gridcontainer=Ext.getCmp('Gridcontainer'); /** * 組建樹 */ Ext.define('TreeModelExtension', { extend: 'Ext.data.Model', //當Model實體類模型被用在某個TreeStore上,而且第一次實例化的時候 ,這些個屬性會添加到Model實體類的的原型(prototype )上 (至於上述代碼,則是經過把他設置爲根節點的時候觸發實例化處理的) fields: [ {name: 'text', type: 'string'}, {name: 'url', type: 'string'} ], }); var buildTree = function (json) { return Ext.create('Ext.tree.Panel', { id:'MenuTree', rootVisible: true, border: false, store: Ext.create('Ext.data.TreeStore', { model:'TreeModelExtension', root: { id:json.id, text:json.text, iconCls: json.iconCls, expanded: json.expanded, children: json.children } }), listeners: { 'itemclick': function (view, record, item, index, e) { var ParentID = record.get('id'); var ShowGrid=CreateGrid(ParentID); Gridcontainer.add(ShowGrid); }, scope: this } }); }; function CreateGrid(ParentID) { var Gridtoolbar = Ext.create('Ext.toolbar.Toolbar', { renderTo: document.body, items: [{ text: '新增', tooltip: '新增一條數據', iconCls: 'Add', handler: function () { RowEditing.cancelEdit(); // Create a model instance var r = new BeiDream.model.BeiDream_NavigationMenu(); Ext.getCmp('NavigationMenuGrid').getStore().insert(0, r); RowEditing.startEdit(0, 0); } }, '-', { text: '編輯', tooltip: '編輯當前選擇行數據', iconCls: 'Pencil', handler: function () { RowEditing.cancelEdit(); var data = Ext.getCmp("NavigationMenuGrid").getSelectionModel().getSelection(); RowEditing.startEdit(data[0].index, 0); }, disabled: true }, '-', { itemId: 'removeUser', text: '刪除', tooltip: '能夠多選刪除多條數據', iconCls: 'Delete', handler: function () { Ext.MessageBox.confirm('提示', '肯定刪除該記錄?', function (btn) { if (btn != 'yes') { return; } var sm = Ext.getCmp('NavigationMenuGrid').getSelectionModel(); RowEditing.cancelEdit(); var store = Ext.getCmp('NavigationMenuGrid').getStore(); store.remove(sm.getSelection()); store.sync(); //根據狀態執行對應的服務器方法,delete,放在remove後才能成功執行服務器方法 if (store.getCount() > 0) { sm.select(0); } }); }, disabled: true }, '-', { itemId: 'gridSync', text: '保存', tooltip: '保存到服務器', iconCls: 'Disk', handler: function () { var grid=Ext.getCmp('NavigationMenuGrid'); grid.store.sync(); grid.store.commitChanges(); //執行commitChanges()提交數據修改。 } }, '-', { itemId: 'gridCancel', text: '取消', tooltip: '取消全部的已編輯數據', iconCls: 'Decline', handler: function () { Ext.MessageBox.confirm('提示', '肯定取消已編輯數據嗎?', function (btn) { if (btn != 'yes') { return; } var grid=Ext.getCmp('NavigationMenuGrid'); grid.store.rejectChanges(); //執行rejectChanges()撤銷全部修改,將修改過的record恢復到原來的狀態 }); } }, '-', { itemId: 'gridrefresh', text: '刷新', tooltip: '從新加載數據', iconCls: 'Arrowrefresh', handler: function () { var grid=Ext.getCmp('NavigationMenuGrid'); grid.store.load(); } } ] }); var RowEditing = Ext.create('Ext.grid.plugin.RowEditing', { // 行編輯模式 clicksToEdit: 2, //雙擊進行修改 1-單擊 2-雙擊 autoCancel: false, saveBtnText: '肯定', cancelBtnText: '取消', errorsText: '錯誤', dirtyText: '你要確認或取消更改', listeners: { // beforeedit: function (rowEditing,e,context) { // if(e.colldx==2 && e.record.data.IsLeaf==false){ // return false; // }else{ // return true; // } // }, cancelEdit: function (rowEditing, context) { // Canceling editing of a locally added, unsaved record: remove it if (context.record.phantom) { //服務器上是否有此條記錄的標誌,true爲沒有 store.remove(context.record); } }, Edit: function (rowEditing, context) { //store.sync(); //根據狀態執行對應的服務器方法,Add/Edit //var IsValidate = ValidateInput(context.record.data, context.record.phantom); // if (!IsValidate) { // grid.store.rejectChanges(); // } } } }); function ValidateInput(data, IsAdd) { var IsValidate; Ext.Ajax.request({ url: ValidateInputUrl, method: 'POST', jsonData: data, params: { IsAdd: IsAdd }, async: false, success: function (response) { var resText = Ext.decode(response.responseText); if (resText.success) { Ext.MessageBox.alert('警告', resText.msg); IsValidate = false; } else { IsValidate = true; } }, failure: function (response, options) { Ext.MessageBox.alert('服務器異常', response.status); } }); return IsValidate; } //多選框變化 function selectchange() { var count = this.getCount(); //刪除 if (count == 0) { Gridtoolbar.items.items[2].disable(); Gridtoolbar.items.items[4].disable(); } else { Gridtoolbar.items.items[2].enable(); Gridtoolbar.items.items[4].enable(); } } //1.定義Model Ext.define("BeiDream.model.BeiDream_NavigationMenu", { extend: "Ext.data.Model", fields: [ { name: 'ID', type: 'int' }, { name: 'ParentID', type: 'int' }, { name: 'ShowName', type: 'string', defaultValue: '名稱......' }, { name: 'IsLeaf', type: 'boolean', defaultValue: true }, { name: 'url', type: 'string' }, { name: 'OrderNo', type: 'int', defaultValue: 1 }, { name: 'iconCls', type: 'string' }, { name: 'Expanded', type: 'boolean', defaultValue: false } ] }); //2.建立store var store = Ext.create("Ext.data.Store", { model: "BeiDream.model.BeiDream_NavigationMenu", autoLoad: true, pageSize: 15, proxy: { type: 'ajax', api: { read: MenuListUrl, //查詢 create: AddUrl, //建立 update: UpdateUrl, //更新,必須真正修改了纔會觸發 destroy: RemoveUrl //刪除 }, reader: { type: 'json', root: 'data' }, writer: { type: 'json', //默認格式 //MVC下後臺使用模型自動進行轉換,若是是普通webform,則配置root:'data',encode:'true',這樣以後就可使用request【data】獲取 writeAllFields: true, //false只提交修改過的字段 allowSingle: false //默認爲true,爲true時,一條數據不以數組形式提交,爲false時,都以數組形式提交,這樣避免了提交了一條數據時,後臺是list模型沒法接收到數據問題 }, listeners: { exception: function (proxy, response, operation) { // var grid=Ext.getCmp('NavigationMenuGrid'); // grid.store.load(); //刪除失敗,數據從新加載 var resText = Ext.decode(response.responseText); Ext.MessageBox.show({ title: '服務器端異常', msg: resText.msg, icon: Ext.MessageBox.ERROR, buttons: Ext.Msg.OK }); } } } }); store.on('beforeload', function (store, options) { var params = { ParentID: ParentID }; Ext.apply(store.proxy.extraParams, params); }); return Ext.create("Ext.grid.Panel", { id: "NavigationMenuGrid", xtype: "grid", store: store, columnLines: true, selModel: { injectCheckbox: 0, listeners: { 'selectionchange': selectchange }, mode: "SINGLE", //"SINGLE"/"SIMPLE"/"MULTI" checkOnly: false //只能經過checkbox選擇 }, selType: "checkboxmodel", columns: [ { xtype: "rownumberer", text: "序號", width: 40, align: 'center' }, { id: "id", text: "ID", width: 40, dataIndex: 'ID', sortable: true, hidden: true }, { id: "id", text: "ParentID", width: 40, dataIndex: 'ParentID', sortable: true, hidden: true }, { text: '名稱', dataIndex: 'ShowName', flex: 1, editor: { xtype: 'textfield', allowBlank: false } }, { text: '是否爲模塊', dataIndex: 'IsLeaf', flex: 1, xtype: 'checkcolumn', editor: { xtype: 'checkbox', cls: 'x-grid-checkheader-editor'} }, { text: '控制器路徑', dataIndex: 'url', flex: 1, editor : { xtype: 'combobox', editable:false, listeners: { //點擊下拉列表事件 expand: function (me, event, eOpts) { var grid=Ext.getCmp('NavigationMenuGrid'); var record = grid.getSelectionModel().getLastSelected(); if(record!=null){ if(record.data.IsLeaf==true){ currentComboBox = me; f_openSelectControllerWin(); }else{ Ext.MessageBox.alert('警告', '只有模塊才擁有控制器!'); } } } } } }, { text: '排序號', dataIndex: 'OrderNo',align:"center", width: 48, flex: 1,editor: { xtype: 'numberfield', allowBlank: false, minValue: 1, maxValue: 150000 } }, { text: '圖標', dataIndex: 'iconCls',align:"center", width: 48,renderer : function(value) { return "<div Align='center' style='height:16px;width:16px' class="+value+"></div>"; } ,editor : { xtype: 'combobox', editable:false, listeners: { //點擊下拉列表事件 expand: function (me, event, eOpts) { currentComboBox = me; f_openIconsWin(); } } } }, { text: '是否展開', dataIndex: 'Expanded', flex: 1, xtype: 'checkcolumn', editor: { xtype: 'checkbox', cls: 'x-grid-checkheader-editor'} } ], plugins: [RowEditing], tbar: Gridtoolbar, bbar: { xtype: "pagingtoolbar", store: store, displayInfo: true, emptyMsg: "沒有記錄" } }); }; });
MVC方便了Ajax的異步實現,而且方便的模型傳參,代碼以下編程
1 /// <summary> 2 /// 返回數據庫新增後的實體,供前臺的extjs的 grid的store更新數據,這樣就不須要進行從新加載store了,刪,改相似 3 /// </summary> 4 /// <param name="Roles"></param> 5 /// <returns></returns> 6 [Anonymous] 7 [HttpPost] 8 public ActionResult Add(List<BeiDream_Role> Roles) 9 { 10 List<BeiDream_Role> AddRoles = new List<BeiDream_Role>(); 11 List<Object> ListObj = RoleService.Add(Roles); 12 if (ListObj.Count == 0) 13 { 14 List<string> msg = new List<string>(); 15 msg.Add("添加角色失敗!"); 16 return this.ExtjsJsonResult(false, msg); 17 } 18 else 19 { 20 foreach (var item in ListObj) 21 { 22 AddRoles.Add(RoleService.GetModelByID(item)); 23 } 24 List<string> msg = new List<string>(); 25 msg.Add("添加角色成功!"); 26 return this.ExtjsJsonResult(true, AddRoles, msg); 27 } 28 29 }
能夠看到我直接經過後臺模型來接收前臺傳遞過來的參數,而不須要去一一解析參數值json
返回值自定義:重寫了ActionResult,實現了extjs須要的返回值後端
1 /// <summary> 2 /// 擴展的jsonResult模型,適用於extjs須要的json數據類型 3 /// </summary> 4 public class JsonResultExtension:ActionResult 5 { 6 public bool success { get; set; } 7 public string msg { get; set; } 8 public object data { get; set; } 9 public long? total { get; set; } 10 public Dictionary<string, string> errors { get; set; } 11 /// <summary> 12 /// 是否序列化爲extjs須要的json格式,不然進行普通序列化 13 /// </summary> 14 public bool ExtjsUISerialize { get; set; } 15 public override void ExecuteResult(ControllerContext context) 16 { 17 18 if (context == null) 19 { 20 throw new ArgumentNullException("context"); 21 } 22 HttpResponseBase response = context.HttpContext.Response; 23 response.ContentType = "application/json"; 24 25 StringWriter sw = new StringWriter(); 26 //IsoDateTimeConverter timeFormat = new IsoDateTimeConverter(); 27 //timeFormat.DateTimeFormat = "yyyy-MM-dd HH:mm:ss"; 28 IsoDateTimeConverter timeFormat = new IsoDateTimeConverter(); 29 timeFormat.DateTimeFormat = "yyyy-MM-dd"; 30 JsonSerializer serializer = JsonSerializer.Create( 31 new JsonSerializerSettings 32 { 33 Converters = new JsonConverter[] { timeFormat }, 34 ReferenceLoopHandling = ReferenceLoopHandling.Ignore, 35 NullValueHandling = NullValueHandling.Ignore //忽略爲null的值序列化 36 37 } 38 ); 39 40 41 using (JsonWriter jsonWriter = new JsonTextWriter(sw)) 42 { 43 jsonWriter.Formatting = Formatting.Indented; 44 45 if (ExtjsUISerialize) 46 serializer.Serialize(jsonWriter, this); 47 else 48 serializer.Serialize(jsonWriter, data); 49 } 50 response.Write(sw.ToString()); 51 52 } 53 }
特性標註及權限驗證,代碼以下api
1 /// <summary> 2 /// 權限攔截 3 /// </summary> 4 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] 5 public class PermissionFilterAttribute : ActionFilterAttribute 6 { 7 /// <summary> 8 /// 權限攔截 9 /// </summary> 10 /// <param name="filterContext"></param> 11 public override void OnActionExecuting(ActionExecutingContext filterContext) 12 { 13 if (!this.CheckAnonymous(filterContext)) 14 { 15 //未登陸驗證 16 if (SessionHelper.Get("UserID") == null) 17 { 18 //跳轉到登陸頁面 19 filterContext.RequestContext.HttpContext.Response.Redirect("~/Admin/User/Login"); 20 } 21 } 22 } 23 /// <summary> 24 /// [Anonymous標記]驗證是否匿名訪問 25 /// </summary> 26 /// <param name="filterContext"></param> 27 /// <returns></returns> 28 public bool CheckAnonymous(ActionExecutingContext filterContext) 29 { 30 //驗證是不是匿名訪問的Action 31 object[] attrsAnonymous = filterContext.ActionDescriptor.GetCustomAttributes(typeof(AnonymousAttribute), true); 32 //是不是Anonymous 33 var Anonymous = attrsAnonymous.Length == 1; 34 return Anonymous; 35 } 36 }
經過寫一個BaseController來進行權限的驗證,這樣就不須要全部須要驗證的Controller加標註了,固然BaseController還能夠增長其餘通用的處理
1 /// <summary> 2 /// Admin後臺系統公共控制器(須要驗證的模塊) 3 /// </summary> 4 [PermissionFilter] 5 public class BaseController:Controller 6 { 7 8 }
非侵入性ORM框架,只須要一個PetaPoco.cs文件就OK了,不過我對其進行了再次封裝,實現了工做單元,仍是上代碼吧
一:封裝
1 public interface IDataRepository<TEntity> : IDependency where TEntity : class 2 { 3 #region 屬性 4 5 /// <summary> 6 /// 獲取 當前實體的查詢數據集 7 /// </summary> 8 Database PetaPocoDB { get; } 9 10 #endregion 11 12 #region 公共方法 13 14 /// <summary> 15 /// 插入實體記錄 16 /// </summary> 17 /// <param name="entity"> 實體對象 </param> 18 /// <returns> 操做影響的行數 </returns> 19 bool Add(TEntity entity); 20 21 /// <summary> 22 /// 批量插入實體記錄集合 23 /// </summary> 24 /// <param name="entities"> 實體記錄集合 </param> 25 /// <returns> 操做影響的行數 </returns> 26 List<object> Add(IEnumerable<TEntity> entities); 27 28 /// <summary> 29 /// 刪除實體記錄 30 /// </summary> 31 /// <param name="entity"> 實體對象 </param> 32 /// <returns> 操做影響的行數 </returns> 33 int Delete(TEntity entity); 34 35 /// <summary> 36 /// 刪除實體記錄集合 37 /// </summary> 38 /// <param name="entities"> 實體記錄集合 </param> 39 /// <returns> 操做影響的行數 </returns> 40 bool Delete(IEnumerable<TEntity> entities); 41 42 /// <summary> 43 /// 更新實體記錄 44 /// </summary> 45 /// <param name="entity"> 實體對象 </param> 46 /// <returns> 操做影響的行數 </returns> 47 int Update(TEntity entity); 48 49 /// <summary> 50 /// 更新實體記錄 51 /// </summary> 52 /// <param name="entity"> 實體對象 </param> 53 /// <returns> 操做影響的行數 </returns> 54 bool Update(IEnumerable<TEntity> entities); 55 /// <summary> 56 /// 根據主鍵ID獲取實體 57 /// </summary> 58 /// <param name="KeyID">主鍵ID</param> 59 /// <returns>實體</returns> 60 TEntity GetModelByID(object KeyID); 61 62 /// <summary> 63 /// 動態查詢,返回dynamic類型的列表 64 /// 請使用標準SQL語句進行查詢(SELECT ... FROM ...) 65 /// </summary> 66 /// <returns></returns> 67 PagedList<dynamic> DynamicPagedList(int pageIndex, int pageSize, Sql sql); 68 69 PagedList<TEntity> PagedList(int pageIndex, int pageSize, string sql, params object[] args); 70 71 PagedList<TEntity> PagedList(int pageIndex, int pageSize, Sql sql); 72 73 PagedList<TDto> PagedList<TDto>(int pageIndex, int pageSize, string sql, params object[] args); 74 75 PagedList<TDto> PagedList<TDto>(int pageIndex, int pageSize, Sql sql); 76 #endregion 77 }
二:使用,具體封裝和使用,你們仍是去下載源碼看吧
1 public class NavigationMenuService : DbContextBase<BeiDream_NavigationMenu>, INavigationMenuService, IDependency 2 { 3 public NavigationMenuService(IUnitOfWork unitOfWork) 4 : base(unitOfWork) 5 { } 6 public List<NavigationMenu> GetNavigationMenu(int id) 7 { 8 var sql = Sql.Builder.Where("ParentID=@0",id); 9 sql.OrderBy("OrderNo ASC"); //默認ASC升序,降序爲DESC 10 List<BeiDream_NavigationMenu> List = this.PetaPocoDB.Fetch<BeiDream_NavigationMenu>(sql); 11 return AutoMapperHelper.GetMapper(List); 12 } 13 public List<NavigationMenu> GetNavigationMenuNoLeaf(int id) 14 { 15 var sql = Sql.Builder.Where("ParentID=@0", id); 16 sql.Where("IsLeaf=@0", false); 17 sql.OrderBy("OrderNo ASC"); //默認ASC升序,降序爲DESC 18 List<BeiDream_NavigationMenu> List = this.PetaPocoDB.Fetch<BeiDream_NavigationMenu>(sql); 19 return AutoMapperHelper.GetMapper(List); 20 } 21 /// <summary> 22 /// 遞歸查詢產品分類列表 23 /// </summary> 24 /// <param name="list">父級產品分類列表</param> 25 public void GetNavigationMenus(ref List<NavigationMenu> list) 26 { 27 foreach (NavigationMenu season in list) 28 { 29 List<NavigationMenu> lstSeason = GetNavigationMenu(season.id); 30 season.children = lstSeason; 31 if (list.Count > 0) 32 { 33 GetNavigationMenus(ref lstSeason); 34 } 35 } 36 } 37 /// <summary> 38 /// 遞歸查詢產品分類列表 39 /// </summary> 40 /// <param name="list">父級產品分類列表</param> 41 public void GetNavigationMenusNoLeaf(ref List<NavigationMenu> list) 42 { 43 foreach (NavigationMenu season in list) 44 { 45 List<NavigationMenu> lstSeason = GetNavigationMenuNoLeaf(season.id); 46 season.children = lstSeason; 47 if (list.Count > 0) 48 { 49 GetNavigationMenusNoLeaf(ref lstSeason); 50 } 51 } 52 } 53 }
目前使用心得最大的好處就是不須要配置即實現了面向接口編程,特別是和MVC結合,實現構造函數注入就更加方便了,固然它還有其餘
功能,好比生命週期惟一實例,單例啊等等,暫時還研究不深,只是簡單應用,你們看看具體實現吧
1 private static void AutofacMvcRegister() 2 { 3 ContainerBuilder builder = new ContainerBuilder(); 4 builder.RegisterGeneric(typeof(DbContextBase<>)).As(typeof(IDataRepository<>)); 5 Type baseType = typeof(IDependency); 6 Assembly[] assemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies() 7 .Select(Assembly.Load).ToArray(); 8 assemblies = assemblies.Union(new[] { Assembly.GetExecutingAssembly() }).ToArray(); 9 builder.RegisterAssemblyTypes(assemblies) 10 .Where(type => baseType.IsAssignableFrom(type) && !type.IsAbstract) 11 .AsImplementedInterfaces().InstancePerLifetimeScope();//InstancePerLifetimeScope 保證生命週期基於請求 12 13 //無效 14 //builder.RegisterType<DefaultCacheAdapter>().PropertiesAutowired().As<ICacheStorage>(); 15 16 builder.RegisterControllers(Assembly.GetExecutingAssembly()); 17 builder.RegisterFilterProvider(); 18 IContainer container = builder.Build(); 19 DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); 20 }
目前也只是簡單應用,先看代碼,它是如何簡化咱們的工做量的
1 public static List<NavigationMenu> GetMapper(List<BeiDream_NavigationMenu> List) 2 { 3 List<NavigationMenu> NavigationMenuList = new List<NavigationMenu>(); 4 foreach (var item in List) 5 { 6 //NavigationMenu DaoModel = new NavigationMenu(); 7 //DaoModel.id = item.ID; 8 //DaoModel.text = item.ShowName; 9 //DaoModel.leaf = item.IsLeaf; 10 //DaoModel.url = item.url; 11 //DaoModel.Expanded = item.Expanded; 12 //DaoModel.children = null; 13 NavigationMenu DaoModel = item.ToDestination<BeiDream_NavigationMenu, NavigationMenu>(); 14 NavigationMenuList.Add(DaoModel); 15 } 16 return NavigationMenuList; 17 }
註釋掉的是不使用automapper以前的代碼,沒註釋掉的是使用automapper,擴展了方法直接一句代碼實現轉化,是否是很easy,固然實
現這些以前,咱們須要給他定義規則,而後還要註冊,代碼以下,具體的請看源碼
1 public class NavigationMenuProfile : Profile 2 { 3 protected override void Configure() 4 { 5 CreateMap<BeiDream_NavigationMenu, NavigationMenu>() 6 .ForMember(dest => dest.id, opt => opt.MapFrom(src => src.ID)) 7 .ForMember(dest => dest.text, opt => opt.MapFrom(src => src.ShowName)) 8 .ForMember(dest => dest.leaf, opt => opt.MapFrom(src => src.IsLeaf)); 9 } 10 }
extjs前臺驗證咱們已經作了,可是客戶端傳來的東西咱們不能徹底相信,後臺須要再次驗證,咱們看到mvc的官方demo。一句話就實現
了驗證,咱們是否是能夠本身作驗證呢,看代碼
1 [Anonymous] 2 public ActionResult SaveUser(BeiDream_User model, List<int> Roles) 3 { 4 var ValidateResult = Validation.Validate(model);//服務器端的驗證 5 if (ValidateResult.IsValid) //驗證成功 6 { 7 bool IsExitUser = UserService.PetaPocoDB.Exists<BeiDream_User>(model.ID); 8 if (!IsExitUser) 9 { 10 FilterGroup userRoleGroup = new FilterGroup(); 11 FilterHelper.CreateFilterGroup(userRoleGroup, null, "UserName", model.UserName, GroupOperatorQueryEnum.and, RuleOperatorQueryEnum.equal); 12 bool IsExist = UserService.IsExist(userRoleGroup); 13 if (IsExist) 14 { 15 List<string> errorName=new List<string>(); 16 errorName.Add("UserName"); 17 ValidationResult error = new ValidationResult("已存在相同的用戶名", errorName); 18 ValidateResult.Add(error); 19 return this.ExtjsFromJsonResult(false,ValidateResult); 20 } 21 else 22 { 23 bool IsSaveSuccess = TransactionService.AddUserAndUserRole(model, Roles); 24 List<string> msg = new List<string>(); 25 msg.Add(IsSaveSuccess ? "用戶信息保存成功!" : "用戶信息保存失敗!"); 26 return this.ExtjsFromJsonResult(true, null, msg); 27 } 28 } 29 else 30 { 31 FilterGroup userRoleGroup = new FilterGroup(); 32 FilterHelper.CreateFilterGroup(userRoleGroup, null, "UserName", model.UserName, GroupOperatorQueryEnum.and, RuleOperatorQueryEnum.equal); 33 FilterHelper.CreateFilterGroup(userRoleGroup, null, "ID", model.ID, GroupOperatorQueryEnum.and, RuleOperatorQueryEnum.notequal); 34 bool IsExist = UserService.IsExist(userRoleGroup); 35 if (IsExist) 36 { 37 List<string> errorName = new List<string>(); 38 errorName.Add("UserName"); 39 ValidationResult error = new ValidationResult("已存在相同的用戶名", errorName); 40 ValidateResult.Add(error); 41 return this.ExtjsFromJsonResult(false, ValidateResult); 42 } 43 else 44 { 45 bool IsSaveSuccess = TransactionService.UpdateUserAndUserRole(model, Roles); 46 List<string> msg = new List<string>(); 47 msg.Add(IsSaveSuccess ? "用戶信息保存成功!" : "用戶信息保存失敗!"); 48 return this.ExtjsFromJsonResult(true, null, msg); 49 } 50 } 51 } 52 else 53 { 54 return this.ExtjsFromJsonResult(false,ValidateResult); //驗證失敗,返回失敗的驗證結果,給出前臺提示信息 55 } 56 }
你們能夠看到前臺傳進來的參數,咱們先進行驗證 var ValidateResult = Validation.Validate(model),驗證的條件咱們是在模型上定義好的,而後判斷驗證是否經過,經過進行下一步動做,不經過,把驗證的結果信息返回前臺,提示給用戶
這個只能算是一個簡單的東西吧,而且感受用起來麻煩,可是我以爲用的熟練了,仍是很不錯的,只是省了手拼SQL的問題嘛,減小了出
錯概率,具體使用仍是看代碼吧
1 [Anonymous] 2 public ActionResult GetUserList(int page, int start, int limit, string UserKeyName, string RoleID) 3 { 4 RemoveSelectId(); 5 PagedList<BeiDream_User> PageList = null; 6 FilterGroup userGroup = GetQueryConditions(UserKeyName, RoleID); 7 PageList = UserService.GetPagedList(page, limit, userGroup); 8 return this.ExtjsGridJsonResult(PageList, PageList.TotalItemCount); 9 } 10 private FilterGroup GetQueryConditions(string UserKeyName, string RoleID) 11 { 12 FilterGroup userGroup = new FilterGroup(); 13 if (!string.IsNullOrEmpty(RoleID)) //用戶角色不爲空時 14 { 15 FilterGroup userRoleGroup = new FilterGroup(); 16 FilterHelper.CreateFilterGroup(userRoleGroup, null, "RoleID", RoleID, GroupOperatorQueryEnum.and, RuleOperatorQueryEnum.equal); 17 //先根據用戶角色查出對應的用戶ID 18 List<BeiDream_User_Role> List = UserRoleService.GetList(userRoleGroup); 19 if (List.Count != 0) //todo,此角色信息爲空狀況下,查到的用戶也應該爲空,目前未處理 20 { 21 if (string.IsNullOrEmpty(UserKeyName)) 22 { 23 //再根據此用戶角色下的用戶ID,由於查出因此用戶ID,查詢條件是或的關係GroupOperatorQueryEnum.or,翻譯出對應用戶的查詢條件,最後查出對應用戶 24 foreach (var item in List) 25 { 26 FilterHelper.CreateFilterGroup(userGroup, null, "ID", item.UserID, GroupOperatorQueryEnum.or, RuleOperatorQueryEnum.equal); 27 } 28 } 29 else 30 { 31 //先翻譯出用戶名查詢條件,與其餘查詢條件是與的關係GroupOperatorQueryEnum.and 32 FilterHelper.CreateFilterGroup(userGroup, null, "UserName", UserKeyName, GroupOperatorQueryEnum.and, RuleOperatorQueryEnum.like); 33 //由於第二個查詢條件是多個查詢條件的結合組成再與第一個查詢條件結合,故放到子FilterGroup中 34 List<FilterGroup> filterGroups = new List<FilterGroup>(); 35 FilterGroup userIDGroup = new FilterGroup(); 36 //再根據此用戶角色下的用戶ID,由於查出因此用戶ID,查詢條件是或的關係GroupOperatorQueryEnum.or,翻譯出對應用戶的查詢條件,最後查出對應用戶 37 foreach (var item in List) 38 { 39 FilterHelper.CreateFilterGroup(userIDGroup, null, "ID", item.UserID, GroupOperatorQueryEnum.or, RuleOperatorQueryEnum.equal); 40 } 41 filterGroups.Add(userIDGroup); 42 userGroup.groups = filterGroups; 43 } 44 } 45 } 46 else 47 { 48 if (!string.IsNullOrEmpty(UserKeyName)) 49 { 50 //先翻譯出用戶名查詢條件,與其餘查詢條件是與的關係GroupOperatorQueryEnum.and 51 FilterHelper.CreateFilterGroup(userGroup, null, "UserName", UserKeyName, GroupOperatorQueryEnum.and, RuleOperatorQueryEnum.like); 52 } 53 } 54 return userGroup; 55 }
緩存也就簡單應用Helper級別,主要用了.net自帶緩存和分佈式Memcached緩存,一個接口,兩個實現
1 /// <summary> 2 /// 緩存接口 3 /// </summary> 4 public interface ICacheStorage 5 { 6 #region 緩存操做 7 /// <summary> 8 /// 添加緩存 9 /// </summary> 10 /// <param name="key"></param> 11 /// <param name="value"></param> 12 void Insert(string key, object value); 13 /// <summary> 14 /// 添加緩存(默認滑動時間爲20分鐘) 15 /// </summary> 16 /// <param name="key">key</param> 17 /// <param name="value">value</param> 18 /// <param name="expiration">絕對過時時間</param> 19 void Insert(string key, object value, DateTime expiration); 20 /// <summary> 21 /// 添加緩存 22 /// </summary> 23 /// <param name="key">key</param> 24 /// <param name="value">value</param> 25 /// <param name="expiration">過時時間</param> 26 void Insert(string key, object value, TimeSpan expiration); 27 /// <summary> 28 /// 得到key對應的value 29 /// </summary> 30 /// <param name="key"></param> 31 /// <returns></returns> 32 object Get(string key); 33 /// <summary> 34 /// 根據key刪除緩存 35 /// </summary> 36 /// <param name="key"></param> 37 void Remove(string key); 38 /// <summary> 39 /// 緩存是否存在key的value 40 /// </summary> 41 /// <param name="key">key</param> 42 /// <returns></returns> 43 bool Exist(string key); 44 /// <summary> 45 /// 獲取全部的緩存key 46 /// </summary> 47 /// <returns></returns> 48 List<string> GetCacheKeys(); 49 /// <summary> 50 /// 清空緩存 51 /// </summary> 52 void Flush(); 53 54 #endregion 55 }
寫博客真的是很累人的事,很敬佩那些能寫連載博客的牛人們,雖然本身作的項目很小,可是以爲寫成博客,要寫的要點仍是不少的
,上面我講的很粗略,可是主要的知識點都講出來了,這個項目其實沒有作完,不打算再繼續了,打算換了,接下來打算使用easyui
+knockout+ef來寫一個完整的權限管理系統,涉及菜單權限、按鈕權限、字段權限等等吧,路很長.....任重而道遠
最後,你們若是以爲有幫助,請點推薦哦!源碼下載地址: