基于MVC+EasyUI的Web开发框架形成之旅–基类控制器CRUD的操作
admin
2023-08-02 16:06:29
0

在上一篇随笔中,我对Web开发框架的总体界面进行了介绍,其中并提到了我的《Web开发框架》的控制器的设计关系,Web开发框架沿用了我的《Winform开发框架》的很多架构设计思路和特点,对Controller进行了封装。使得控制器能够获得很好的继承关系,并能以更少的代码,更高效的开发效率,实现Web项目的开发工作,整个控制器的设计思路如下所示。

从上图的设计里面可以看到,我把主要能通过抽象封装的CRUD方法都放到了BusinessController类里面,本文继续详细介绍这个Web框架控制器类的CRUD具体实现,以便使得大家了解我的整个Web开发框架的基类控制器的工作原理。

1、基类的插入操作

我们知道,一般常规的插入操作是很普遍的操作,那么我们在MVC的Web界面上是如何调用的,后台又是如何进行数据的处理的呢?
在MVC的View视图代码里面,我们添加数据的时候,javascript脚本代码是这样的:

var postData = $(\"#ffAdd\").serializeArray();
$.post(\"/Information/Insert\", postData, function (data) {
    if (data = \"true\") {
        //添加成功  1.关闭弹出层,2.刷新DataGird
        $.messager.alert(\"提示\", \"添加成功\");
        $(\"#DivAdd\").dialog(\"close\");
        $(\"#grid\").datagrid(\"reload\");
        $(\"#ffAdd\").form(\"clear\");

        //本页面的类型为【通知公告】,固定不变
        $(\"#Category\").val(\"通知公告\");
    }
    else {
        $.messager.alert(\"提示\", \"添加失败,请您检查\");
    }
});

其中的serializeArray就把该表单要提交的数据序列号到一个字符串里面了,里面的数据可能类似A=a&B=b&C=c 这样的字符串里面了,通过POST调用控制器Information的Insert方法,实现数据的插入。由于控制器Information是具体业务类,因此它继承自BusinessController也就是会调用BusinessController控制器的Insert方法。
如字典数据添加的界面如下所示。

那么后台的接收方法如何呢?其实后台是把数据序列化到了一个FormCollection对象的集合里面了,但是,我们还可以使用对象T(实体类),让这些数据集合赋值给对应的实体对象属性,如下就是我的后台控制器的插入方法,它的参数是一个实体类T,这样我们直接调用业务操作类就可以插入了,代码很简单易懂。

/// 
/// 插入指定对象到数据库中
/// 
/// 指定的对象
/// 执行操作是否成功。
public virtual ActionResult Insert(T info)
{bool result = false;
    if (info != null)
    {
        result = baseBLL.Insert(info);
    }
    return Content(result);
}

2、基类的更新操作

上面我们看了插入数据的操作,可能大家对下面介绍的数据更新操作,可能也已经有了一些了解了,其实它和插入操作的方法很类似的。
更新操作的视图View中脚本代码如下所示, 它通过控制器Information的Update方法进行更新数据。

var ID = $(\"#ID1\").val();
var postData = $(\"#ffEdit\").serializeArray();
$.post(\"/Information/Update?ID=\" + ID, postData, function (date) {
    if (date == \"true\") {
        //修改成功,关闭弹出层,刷新DataGird
        $.messager.alert(\"提示\", \"修改成功\");
        $(\"#DivEdit\").dialog(\'close\');
        $(\"#grid\").datagrid(\"reload\");
    }
    else {
        $.messager.alert(\"提示\", \"修改失败,请您检查\");
    }
});

由于控制器Information是具体业务类,因此它继承自BusinessController也就是会调用BusinessController控制器的Update方法。
和上面的插入操作一样,后台是把数据序列化到了一个FormCollection对象的集合里面了,我们可以使用类似和插入方法的操作,如下所示。

/// 
/// 更新对象属性到数据库中
/// 
/// 指定的对象
/// 主键ID的值
/// 执行成功返回true,否则为false
public virtual ActionResult Update(T info, string id)
{
    bool result = baseBLL.Update(info, id);
    return Content(result);
}

但是,如果使用以上的代码作为更新数据的代码,那么在编辑界面里,如果只是显示编辑部分表的数据,那么可能导致很多属性会被初始化为实体类的默认值,显然这样不符合我们的要求,我们可能只是进行部分更新,那么我们进行部分更新的控制器方法应该如何设计呢?
前面我们说到,数据会被序列号到一个FormCollection对象集合里面,更新方法也一样,那么我们可以把更新操作的接口定义为如下代码所示,视图操作代码不变化:

/// 
/// 更新对象属性到数据库中
/// 
/// 指定的对象
/// 主键ID的值
/// 执行成功返回true,否则为false
public virtual ActionResult Update(string id, FormCollection formValues)

我们可以通过调试的方法,查询到FormCollection里面的值就是我们更新界面里面的数据(注意:可能是实体类的部分数据)。但使用了这个方法后,我们还需要把FormCollection对象里面的数据转换为实体类的信息,我们才好调用BaseBLL里面的接口进行更新数据。但是不同的实体类,有不同的属性,我们如何能够抽象把他们的属性都赋值了呢?
答案是通过反射属性方式,把FormCollection里面属性的值赋值给对应实体类属性的值。下面我们来介绍下具体的代码实现了。

/// 
/// 更新对象属性到数据库中
/// 
/// 指定的对象
/// 主键ID的值
/// 执行成功返回true,否则为false
public virtual ActionResult Update(string id, FormCollection formValues)
{

    T obj = baseBLL.FindByID(id);
    if (obj != null)
    {
        //遍历提交过来的数据(可能是实体类的部分属性更新)
        foreach (string key in formValues.Keys)
        {
            string value = formValues[key];
            System.Reflection.PropertyInfo propertyInfo = obj.GetType().GetProperty(key);
            if (propertyInfo != null)
            {
                try
                {
                    // obj对象有key的属性,把对应的属性值赋值给它(从字符串转换为合适的类型)
                    //如果转换失败,会抛出InvalidCastException异常
                    propertyInfo.SetValue(obj, Convert.ChangeType(value, propertyInfo.PropertyType), null);
                }
                catch { }
            }
        }
    }

    bool result = baseBLL.Update(obj, id);
    return Content(result);
}

通过对象propertyInfo的SetValue方法,可以把字符串的值,转换为实体类对应属性类型的值,顺利进行赋值。

如果是业务类需要提交一些HTML的代码,那么我们需要在具体的业务类里面,重写插入、更新方法并设置一下 [ValidateInput(false)] 标识才可以。

[ValidateInput(false)]
public override ActionResult Insert(InformationInfo info)
{
    info.Editor = CurrentUser.Name;
    info.EditTime = DateTime.Now;

    return base.Insert(info);
}

[ValidateInput(false)]
public override ActionResult Update(string id, FormCollection formValues)
{
    return base.Update(id, formValues);
}

如通知公告的内容编辑界面如下所示。

3、基类的获取对象数据方法

我们在很多接口里面,都要求获取单一对象的数据信息,我在基类接口里面定义了一个FindByID方法,就是从业务对象里面,根据主键ID信息,获取一个对象的数据,把他转换为Json传递到View视图里面使用即可。

/// 
/// 查询数据库,检查是否存在指定ID的对象
/// 
/// 对象的ID值
/// 存在则返回指定的对象,否则返回Null
public virtual ActionResult FindByID(string id)
{
    ActionResult result = Content(\"\");
    T info = baseBLL.FindByID(id);
    if (info != null)
    {
        result = JsonDate(info);
    }

    return result;
}

其中的JsonDate方法是为了避免日期类型的数值在序列化中出现错误格式,包装的一个方法,如下所示。

/// 
/// 返回处理过的时间的Json字符串
/// 
/// 
/// 
public ContentResult JsonDate(object date)
{
    var timeConverter = new IsoDateTimeConverter { DateTimeFormat = \"yyyy-MM-dd HH:mm:ss\" };
    return Content(JsonConvert.SerializeObject(date, Formatting.Indented, timeConverter));
}

在View视图里面使用控制器方法,绑定数据到查看界面里面的代码如下所示。

//绑定查看详细信息的方法
function BindViewInfo() {
    var ID = $(\"#grid\").datagrid(\'getSelections\')[0].ID;            
    //发送请求
    $.getJSON(\"/Information/FindByID?r=\" + Math.random() + \"&id=\" + ID, function (info) {
        $(\"#ID2\").val(info.ID);
        $(\"#Title2\").text(info.Title);
        $(\"#Content2\").html(info.Content);
        $(\"#Attachment_GUID2\").text(info.Attachment_GUID);
        $(\"#Editor2\").text(info.Editor);
        $(\"#EditTime2\").text(info.EditTime);

        ShowUpFiles(info.Attachment_GUID, \'divViewAttach\');
    });
}

具体效果如下所示:

4、基类删除操作方法

在GridView里面,我们提供了删除数据的按钮,具体视图里面使用的代码如下所示。

//然后确认发送异步请求的信息到后台删除数据
$.messager.confirm(\"删除确认\", \"您确认删除选定的记录吗?\", function (deleteAction) {
    if (deleteAction) {
        $.get(\"/Information/DeletebyIds\", postData, function (data) {
            if (data == \"true\") {
                $.messager.alert(\"提示\", \"删除选定的记录成功\");
                $(\"#grid\").datagrid(\"reload\");
            }
            else {
                $.messager.alert(\"提示\", data);
            }
        });
    }
});

后台控制器的基类删除方法如下所示。

/// 
/// 删除多个ID的记录
/// 
/// 多个id组合,逗号分开(1,2,3,4,5)
/// 
public virtual ActionResult DeleteByIds(string ids)
{bool result = false;
    if (!string.IsNullOrEmpty(ids))
    {
        string[] idArray = ids.Split(new char[] { \',\' });
        foreach (string strId in idArray)
        {
            if (!string.IsNullOrEmpty(strId))
            {
                baseBLL.Delete(strId);
            }
        }
        result = true;
    }
    return Content(result);
}

以上就是基类控制器增删改查的一些通用方法的封装,业务对象控制器类,如果有特殊的需要,可以对方法进行重写即可,非常方便使用,从而减少了很多重复编写的代码,并可以使得页面的操作统一化,提高生产效率。

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
python清除字符串里非数字... 本文实例讲述了python清除字符串里非数字字符的方法。分享给大家供大家参考。具体如下: impor...