zoukankan      html  css  js  c++  java
  • 基于MVC4+EasyUI的Web开发框架形成之旅--MVC控制器的设计

    自从上篇《基于MVC4+EasyUI的Web开发框架形成之旅--总体介绍》总体性的概括,得到很多同行的关注和支持,不过上一篇主要是介绍一个总体的界面效果和思路,本系列的文章将逐步介绍其中的细节,本文主要介绍整个Web开发框架中的MVC控制器的设计。在设计之初,我就希望尽可能的减少代码,提高编程模型的统一性。因此希望能够以基类继承的方式,和我Winform开发框架一样,尽可能通过基类,而不是子类的重复代码来实现各种通用的操作。

    1、登录控制的控制器基类设计

    我们知道,一般我们创建一个MVC的控制器,都是基于Controller这样的基类来实现。如下代码所示。

        public class TestController : Controller
        {
            //
            // GET: /Test/
    
            public ActionResult Index()
            {
                return View();
            }
    
        }

    在我的Winform开发框架里面,用到了泛型的类型,非常方便实现业务逻辑和数据访问基类的设计,控制器是否也可以这样做的呢?

    我们知道,一般的MVC控制器需要验证用户是否已经登陆了,这也是很多常见Web操作前的验证,还有对异常的处理,在MVC的基类,可以一并进行记录(这个非常不错),于是我们先来设计一个验证用户身份是否登陆的基类BaseController

        /// <summary>
        /// 所有需要进行登录控制的控制器基类
        /// </summary>
        public class BaseController : Controller 
        {
            /// <summary>
            /// 当前登录的用户属性
            /// </summary>
            public UserInfo CurrentUserInfo { get; set; }
    
            /// <summary>
            /// 重新基类在Action执行之前的事情
            /// </summary>
            /// <param name="filterContext">重写方法的参数</param>
            protected override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                base.OnActionExecuting(filterContext);
                //得到用户登录的信息
                CurrentUserInfo = Session["UserInfo"] as UserInfo;
    
                //判断用户是否为空
                if (CurrentUserInfo == null)
                {
                    Response.Redirect("/Login/Index");
                }
            }
    
            protected override void OnException(ExceptionContext filterContext)
            {
                base.OnException(filterContext);
    
                //错误记录
                WHC.Framework.Commons.LogTextHelper.Error(filterContext.Exception);
    
                // 当自定义显示错误 mode = On,显示友好错误页面
                if (filterContext.HttpContext.IsCustomErrorEnabled)
                {
                    filterContext.ExceptionHandled = true;
                    this.View("Error").ExecuteResult(this.ControllerContext);
                }
            }
    ........................ }

    有了这个基类,我们在主页的Home控制类,就可以使用用户信息对象了进行操作了,而且必须要求客户登陆了。

        public class HomeController : BaseController
        {
            public ActionResult Index()
            {
                if (CurrentUserInfo != null)
                {
                    ViewBag.FullName = CurrentUserInfo.FullName;
                    ViewBag.Name = CurrentUserInfo.Name;
                }
                return View();
            }
    ................
        }

    2、数据访问业务基类控制器的设计

    我在我的Winform开发框架里面,对很多基类都使用泛型进行设计,这样可以传递相应的数据类型到基类里面进行处理,如下面的BLL层的业务对象定义代码如下所示。

    namespace WHC.Security.BLL
    {
        /// <summary>
        /// 角色信息业务管理类
        /// </summary>
        public class Role : BaseBLL<RoleInfo>
        {
    
    ....................
        /// <summary>
        /// 业务基类对象
        /// </summary>
        /// <typeparam name="T">业务对象类型</typeparam>
        public class BaseBLL<T> where T : BaseEntity, new()
        {
    
            /// <summary>
            /// 插入指定对象到数据库中
            /// </summary>
            /// <param name="obj">指定的对象</param>
            /// <returns>执行操作是否成功。</returns>
            public virtual bool Insert(T obj)
            {
                return baseDal.Insert(obj);
            }
    
    ............

    业务对象Role,要求传入RoleInfo给基类处理,这样基类就能定义到都对应的T为具体的RoleInfo类型了。在MVC的控制器是否也可以这样做呢?当然可以,下面是我定义的一个控制器继承关系图。

    上面的介绍也已经比较明白了,其实就是在BusinessController<B, T>里面传入了两个参数,定义代码如下所示。

        /// <summary>
        /// 本控制器基类专门为访问数据业务对象而设的基类
        /// </summary>
        /// <typeparam name="B">业务对象类型</typeparam>
        /// <typeparam name="T">实体类类型</typeparam>
        public class BusinessController<B, T> : BaseController
            where B : class
            where T : WHC.Framework.ControlUtil.BaseEntity, new()
        {
    
            /// <summary>
            /// 插入指定对象到数据库中
            /// </summary>
            /// <param name="info">指定的对象</param>
            /// <returns>执行操作是否成功。</returns>
            public virtual ActionResult Insert(T info)
            {
                bool result = false;
                if (info != null)
                {
                    result = baseBLL.Insert(info);
                }
                return Content(result);
            }
    
    ................

    我根据传入的BLL业务对象类型B,对象实体类类型T,那么我们就可以构造对应的baseBLL对象,然后调用其基类接口实现基本的操作,如插入,删除,更新,查找等等,这样的模式就和我的Winform开发框架的理念非常吻合了。

    我们以角色控制器来说明,它的定义如下所示,如果不需要实现额外的接口(除了常见的操作),基本上不需要写任何代码了,因为所有很多常见的操作,都已经封装在了基类控制器BusinessController<B, T>里面了。

        /// <summary>
        /// 角色业务操作控制器
        /// </summary>
        public class RoleController : BusinessController<Role, RoleInfo>
        {
            public RoleController() : base()
            {
            }
    
    ...............

    对于一些需要特殊数据处理的操作,可以增加一些自定义的接口函数,也可以重写基类的一些接口,实现数据的相应处理。如我的菜单界面显示中,需要根据缩进的层级对菜单名称进行缩进,以便更好的展示它们的层级结构,那么我就需要对分页函数进行重写了,如下代码所示是整个菜单Menu类的控制器类代码。

        public class MenuController : BusinessController<Menu, MenuInfo>
        {
            public override ActionResult FindWithPager()
            {
                string where = GetPagerCondition(); //基类实现
                PagerInfo pagerInfo = GetPagerInfo(); //基类实现            
                List<MenuInfo> list = baseBLL.FindWithPager(where, pagerInfo);
                list = CollectionHelper<MenuInfo>.Fill("-1", 0, list, "PID", "ID", "Name");
    
                //Json格式的要求{total:22,rows:{}}
                //构造成Json的格式传递
                var result = new { total = pagerInfo.RecordCount, rows = list };
                return JsonDate(result);
            }
    
            /// <summary>
            /// 用作下拉列表的菜单Json数据
            /// </summary>
            /// <returns></returns>
            public ActionResult GetDictJson()
            {
                List<MenuInfo> list = baseBLL.GetAll();
                list = CollectionHelper<MenuInfo>.Fill("-1", 0, list, "PID", "ID", "Name");
    
                List<CListItem> itemList = new List<CListItem>();
                foreach (MenuInfo info in list)
                {
                    itemList.Add(new CListItem(info.Name, info.ID));
                }
                return Json(itemList, JsonRequestBehavior.AllowGet);
            }
        }

    我们来看看一段HTML页面里面,使用javascript脚本调用控制器API来实现数据的绑定的操作,也就是使用示例。

                $.getJSON("/Role/FindById?r=" + Math.random() + "&id=" + id, function (json) {
                    $("#txtID").val(json.ID);
                    $("#txtName").val(json.Name);
                    $("#txtNote").val(json.Note);
                });

    上面这个很标准的接口FindById是业务基类控制器BusinessController<B, T>里提供的。

    当然,BusinessController里面可以类似我Winform开发框架里面基类一样,提供很丰富的操作接口,如返回列表Json集合,增删改查的操作及返回,分页数据的返回,以及一些特殊的操作都可以实现。而这些都不需要子类进行任何实现。

    如下面实际案例的用户登陆日志,里面的界面功能还是很丰富的,当他的控制器业务类不需要任何实现,只需要继承基类即可。

        public class LoginLogController : BusinessController<LoginLog, LoginLogInfo>
        {
            public LoginLogController() : base()
            {
            }
    
        }

    界面部分代码如下所示。

            //实现对DataGird控件的绑定操作
            function InitGrid(queryData) {
                $('#grid').datagrid({   //定位到Table标签,Table标签的ID是grid
                    url: '/LoginLog/FindWithPager',   //指向后台的Action来获取当前用户的信息的Json格式的数据
                    title: '用户登陆日志', 
                    //下面的这些属性如果谁不太清楚的话我建议去官方网站去学习
                    iconCls: 'icon-view',
                    height: 450,
                    nowrap: true,
                    autoRowHeight: false,
                    striped: true,
                    collapsible: true,
                    pagination: true,
                    rownumbers: true,
                    //sortName: 'ID',    //根据某个字段给easyUI排序
                    sortOrder: 'asc',
                    remoteSort: false,
                    idField: 'ID',
                    queryParams: queryData,  //异步查询的参数
                    columns: [[
                        { field: 'ck', checkbox: true },   //选择
                        { title: 'ID', field: 'ID',  40, sortable: true },  //主键
                         { title: '登录用户ID', field: 'User_ID',  80, sortable: true },
                         { title: '登录名称', field: 'LoginName',  80, sortable: true },
                         { title: '真实名称', field: 'FullName',  80, sortable: true },
                         { title: '日志描述', field: 'Note',  100, sortable: true },
                         { title: 'IP地址', field: 'IPAddress',  100, sortable: true },
                         { title: 'Mac地址', field: 'MacAddress',  120, sortable: true },
                         { title: '系统编号', field: 'SystemType_ID',  120, sortable: true },
                         { title: '记录日期', field: 'LastUpdated',  120, sortable: true },
                    ]],
                    toolbar: [{
                        id: 'btnAdd',
                        text: '添加',
                        iconCls: 'icon-add',
                        handler: function () {                        
                            ShowAddDialog();//实现添加记录的页面
                        }
                    }, '-', {
                        id: 'btnEdit',
                        text: '修改',
                        iconCls: 'icon-edit',
                        handler: function () {                        
                            ShowEditOrViewDialog();//实现修改记录的方法
                        }
                    }, '-', {
                        id: 'btnDelete',
                        text: '删除',
                        iconCls: 'icon-remove',
                        handler: function () {                        
                            Delete();//实现直接删除数据的方法
                        }
                    }, '-', {
                        id: 'btnView',
                        text: '查看',
                        iconCls: 'icon-table',
                        handler: function () {                        
                            ShowEditOrViewDialog("view");//实现查看记录详细信息的方法
                        }
                    }, '-', {
                        id: 'btnReload',
                        text: '刷新',
                        iconCls: 'icon-reload',
                        handler: function () {
                            //实现刷新栏目中的数据
                            $("#grid").datagrid("reload");
                        }
                    }]
                });
    
                $('#grid').datagrid({
                    onDblClickRow: function (rowIndex, rowData) {
                        $('#grid').datagrid('uncheckAll');
                        $('#grid').datagrid('checkRow', rowIndex);
                        ShowEditOrViewDialog();
                    }
                });
            }

    这个就是我的控制器设计的中心思想了,下一篇继续介绍整体的MVC系列的Web开发框架,介绍其中Web界面部分的处理和相关经验,希望大家多多提出宝贵的意见。

    基于MVC4+EasyUI的Web开发框架的系列文章:

    基于MVC4+EasyUI的Web开发框架形成之旅--总体介绍

    基于MVC4+EasyUI的Web开发框架形成之旅--MVC控制器的设计

    基于MVC4+EasyUI的Web开发框架形成之旅--界面控件的使用

    基于MVC4+EasyUI的Web开发框架形成之旅--附件上传组件uploadify的使用

    基于MVC4+EasyUI的Web开发框架形成之旅--框架总体界面介绍

    基于MVC4+EasyUI的Web开发框架形成之旅--基类控制器CRUD的操作

    基于MVC4+EasyUI的Web开发框架形成之旅--权限控制

    基于MVC4+EasyUI的Web开发框架经验总结(1)-利用jQuery Tags Input 插件显示选择记录

    基于MVC4+EasyUI的Web开发框架经验总结(2)- 使用EasyUI的树控件构建Web界面

    基于MVC4+EasyUI的Web开发框架经验总结(3)- 使用Json实体类构建菜单数据

    基于MVC4+EasyUI的Web开发框架经验总结(4)--使用图表控件Highcharts

    基于MVC4+EasyUI的Web开发框架经验总结(5)--使用HTML编辑控件CKEditor和CKFinder

    基于MVC4+EasyUI的Web开发框架经验总结(6)--在页面中应用下拉列表的处理

    基于MVC4+EasyUI的Web开发框架经验总结(7)--实现省份、城市、行政区三者联动

    基于MVC4+EasyUI的Web开发框架经验总结(8)--实现Office文档的预览

    基于MVC4+EasyUI的Web开发框架经验总结(9)--在Datagrid里面实现外键字段的转义操作

    基于MVC4+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出

    基于MVC4+EasyUI的Web开发框架经验总结(11)--使用Bundles处理简化页面代码

    基于MVC4+EasyUI的Web开发框架经验总结(12)--利用Jquery处理数据交互的几种方式

    基于MVC4+EasyUI的Web开发框架经验总结(13)--DataGrid控件实现自动适应宽带高度

    基于MVC4+EasyUI的Web开发框架经验总结(14)--自动生成图标样式文件和图标的选择操作

  • 相关阅读:
    序列号问题(入库检带序列号,冲销入库无序列号(变态情况))
    sm30表维护做排序
    HR函数学习03——维护信息类型1008
    HR函数学习02——分配组织单位
    机器学习知识积累
    机器学习数学知识积累之高等数学微积分
    机器学习数学知识积累之线性代数解析几何,微积分
    机器学习数学知识积累之数理统计
    在博客园使用LaTex编辑学术论文级别的data science文章
    机器学习数学知识积累之概率论
  • 原文地址:https://www.cnblogs.com/wuhuacong/p/3284628.html
Copyright © 2011-2022 走看看