后台管理系统

extjs+MVC4+PetaPoco+AutoFac+AutoMapper后台管理系统(附源码)

 
 

前言

本项目使用的开发环境及技术列举如下:
1、开发环境
IDE:VS2010+MVC4
数据库:SQLServer2008
2、技术
前端:Extjs
后端:
(1)、数据持久层:轻量级ORM框架PetaPoco
(2)、依赖注入:AutoFac
(3)、对象关系映射:AutoMapper
(4)、数据验证(MVC自带的验证封装使用)
(5)、SQL翻译机
(6)、缓存

以上使用都参考或直接借鉴使用了园子内牛人们的代码,只是学习交流使用而已,还请勿怪,我为了简便,没有分多个类库,而是以文
件夹的形式分的,大家可以根据文件夹分成类库也是一样的。好了,废话不多说,还是先上几张图大家看看吧,如果有兴趣再往下看

 

项目截图

要点一:Extjs

本项目虽然功能不多,但是基本已经涵盖了extjs的所有基本用法了,对于一般的extjs初学者或是简单应用的开发应该是足够了,后 
台开发主要在tab、grid、treegrid的用法比较多,也是比较麻烦的地方,下面直接上代码,大家看看

首页布局:

 View Code

Grid行内增删改查:

复制代码
  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: "序号",  40, align: 'center' },
298         { id: "id", text: "ID",  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',
         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: "序号",  40, align: 'center' },
            { id: "id", text: "ID",  40, dataIndex: 'ID', sortable: true, hidden: true },
            { id: "id", text: "ParentID",  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",  48, flex: 1,editor: {
                xtype: 'numberfield',
                allowBlank: false,
                minValue: 1,
                maxValue: 150000
            } },
            { text: '图标', dataIndex: 'iconCls',align:"center",  48,renderer : function(value) {
                    return "<div Align='center' style='height:16px;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的传参绑定,返回值自定义

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         }
复制代码

可以看到我直接通过后台模型来接收前台传递过来的参数,而不需要去一一解析参数值

返回值自定义:重写了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     }
复制代码

特性标注及权限验证,代码如下

复制代码
 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  

  非侵入性ORM框架,只需要一个PetaPoco.cs文件就OK了,不过我对其进行了再次封装,实现了工作单元,还是上代码吧

      一:封装

 View Code

     二:使用,具体封装和使用,大家还是去下载源码看吧

 View Code

要点四:依赖注入框架Autofac

目前使用心得最大的好处就是不需要配置即实现了面向接口编程,特别是和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         }
复制代码

要点五;对象关系映射AutoMapper

目前也只是简单应用,先看代码,它是如何简化我们的工作量的

复制代码
 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翻译机

这个只能算是一个简单的东西吧,并且感觉用起来麻烦,但是我觉得用的熟练了,还是很不错的,只是省了手拼SQL的问题嘛,减少了出 
错几率,具体使用还是看代码吧

 View Code

要点八:缓存

 缓存也就简单应用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来写一个完整的权限管理系统,涉及菜单权限、按钮权限、字段权限等等吧,路很长.....任重而道远

最后,大家如果觉得有帮助,请点推荐哦!源码下载地址:

猛戳这里BeiDream.part1.rar!

猛戳这里BeiDream.part2.rar!

原文地址:https://www.cnblogs.com/Leo_wl/p/4456853.html