• 后台管理系统


    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!

  • 相关阅读:
    mybatis动态sql和分页
    mybatis入门
    IDEA
    Linux环境搭建
    svn
    jwt
    Vuex
    SPA项目开发之CRUD+表单验证
    JavaScript可视化框架——Echarts
    python+selenium六:隐式等待
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4456853.html
Copyright © 2020-2023  润新知