[转载]使用NVelocity快速实现Flexigrid

[转载]使用NVelocity快速实现Flexigrid – Ariel Lu – 博客园.

自从去年偶然间发现Flexigrid这款JQuery的表格控件,就被它深深地吸引住了,华丽的外表、强大的功能、灵活的扩展性,最关键的是它不臃肿。如果追求功能强大,倒不如去使用ExtJs了。前段时间园友华磊给出了Flexigrid的ASP.NET解决方案,但我觉得封装成用户控件丧失了灵活性,而且它不再是一个客户端控件,不能按照我们的想法去随心所欲地操纵它。

既 然我们想保持它在前端的灵活性,只有另辟蹊径,从其它方面着手去简化工作。每次使用它,在后台获取数据,转成JSON格式也是一个比较繁琐的工作,有没有 一种方案能简化这些步骤,每次只需通过简单的配置和一两条SQL语句就能达到我们想要的效果呢?答案当然是肯定的。于是我想到了用模板引擎 NVelcity来实现这个方案。只要能把Flexigrid异步请求的参数能在SQL语句中使用,就可以解决这个问题了。

于是我们需要一个通用的WebService方法来接受、处理Flexigrid的参数:首先处理Flexigrid本身在获取数据的时候用的六个参数,代码如下:

//处理FlexiGrid的参数
//$page  第几页
//$rp  每页的条数
//$sortname  排序字段
//$sortorder  排序方向
string[] flexiGridParameters = { "page", "rp", "sortname", "sortorder", 
                                   "query", "qtype" };
Dictionary<string, object> parameters = new Dictionary<string, object>();
foreach (string flexiGridParameter in flexiGridParameters)
{
    string valueOfFlexiGridParameter = Context.Request.Params[flexiGridParameter];
    if (!string.IsNullOrEmpty(valueOfFlexiGridParameter))
    {
        parameters.Add(flexiGridParameter, valueOfFlexiGridParameter);
    }
}

有时候除了默认的这几个参数,我们还需要一些自定义的参数,为了方便处理,自定义参数需以”param_”开头:

//加入自定义参数,以 "param_" 开头
foreach (string userDefinedParameterName in Context.Request.Params.AllKeys
    .Where(o => o.StartsWith("param_")))
{
    parameters.Add(userDefinedParameterName,
        Context.Request.Params[userDefinedParameterName]);
}

另外page和rp为别表示页数和每页的条数,而我们需要的是起始条数和结束条数:

//将page和rp两个参数转成整数,再加入下面两个参数,方便写sql语句
//$startIndex  开始的行号
//$endIndex  结束的行号
int page = 1;
if (parameters.ContainsKey("page") && parameters.ContainsKey("rp"))
{
    page = Convert.ToInt32(parameters["page"]);
    int rp = Convert.ToInt32(parameters["rp"]);
    parameters["page"] = page;
    parameters["rp"] = rp;
    parameters.Add("startIndex", (page - 1) * rp + 1);
    parameters.Add("endIndex", page * rp);
}

好了,需要的参数都有了,剩下的工作就是如果写出一条用上上述参数的SQL语句并且动态地去解析它,在这里我选择了模板引擎NVelcity(本文中使用的是Castle的1.1版,这里有详细介绍)。现在我们要使用模板语言返回一个我们需要的数据结构,模板中定义如下:

#*
* 已有参数说明
$page  第几页
$rp  每页的条数
$sortname  排序字段
$sortorder  排序方向
$startIndex  开始的行号
$endIndex  结束的行号
$param_xxxx  自定义参数,xxxx为任意字符串

* 需要返回的数据结构说明
$result.rowsSql  获取数据的sql语句(必须有)
$result.totalSql  分页时取数据总数的sql语句(分页时必须有)
$result.id  FlexiGrid中的行id所对应的字段名(需要行id时指定,不指定时行id为空)
*#

这个时候又出现新的问题了,很多情况下SQL语句是一段很长的文本,而模板语言不支持换行,写在一行中可阅读性很差,显然是不符合要求的。这个时候就需要扩展一个模板语言中解析字符串的函数,把SQL语句写在另一个文本文件中,在模板中使用这个方法就可以啦。

static object ReadFileContent(object[] parameters)
{
    if (parameters.Length < 1)
    {
        return string.Empty;
    }
    DirectoryInfo info = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory
        + NVelocityConstants.TEMPLATE_DIRECTORY);
    FileInfo[] files = info.GetFiles(parameters[0].ToString(),
        SearchOption.AllDirectories);
    if (files.Length > 0)
    {
        string content = File.ReadAllText(files[0].FullName);
        List<string> argList = new List<string>();
        if (!string.IsNullOrEmpty(content))
        {
            for (int i = 1; i < parameters.Length; i++)
            {
                argList.Add(parameters[i] != null ?
                    parameters[i].ToString() : string.Empty);
            }
        }
        if (argList.Count > 0)
        {
            string[] ps = argList.ToArray();
            content = string.Format(content, ps);
        }
        return content;
    }
    return string.Empty;
}

回到刚才的WebService方法中,使用NVelocity解析刚才的模板:

//解析模板,取回FlexiGrid所需的sql语句,result类型为KeyValueObject
//$result.rowsSql  获取数据的sql语句(必须有)
//$result.totalSql  分页时取数据总数的sql语句(分页时必须有)
//$result.id  FlexiGrid中的行id所对应的字段名(需要行id时指定,不指定时行id为空)
NVelocityHelper velocity = new NVelocityHelper();
//注入工具类和参数
velocity.Add("helper", new HelperDuck());
foreach (string parameterName in parameters.Keys)
    velocity.Add(parameterName, parameters[parameterName]);
//得到模板执行结果
object result = velocity.GetResultFromVm(templateFileName);
if (result is KeyValueObject)
{
    KeyValueObject keyValueResult = (KeyValueObject)result;
    string rowsSql = string.Format("{0}", keyValueResult.GetInvoke("rowsSql"));
    string totalSql = string.Format("{0}", keyValueResult.GetInvoke("totalSql"));
    string id = string.Format("{0}", keyValueResult.GetInvoke("id"));

现在SQL语句已经有了,执行它,并序列化成JSON结构:

DataTable dt = Utils.ExecuteTable(rowsSql);
List<FlexiGridRow> rows = new List<FlexiGridRow>();
foreach (DataRow dr in dt.Rows)
{
    rows.Add(new FlexiGridRow()
    {
        id = dt.Columns.Contains(id) ? string.Format("{0}", dr[id]) : string.Empty,
        cell = Utils.DbObjectArrToCsStringArr(dr.ItemArray)
    });
}
int total = -1;
if (!string.IsNullOrEmpty(totalSql))
    total = Convert.ToInt32(Utils.ExecuteTable(totalSql).Rows[0][0]);

object flexiGridResult = new
{
    page = page,
    total = total > -1 ? total : rows.Count,
    rows = rows
};
Context.Response.Write(new JavaScriptSerializer().Serialize(flexiGridResult));

至此准备工作就全部完成了,下面我们通过一个示例来看一下效果如何:

1.首先新建一个文本文件用来存放SQL语句:

SELECT CompanyName, ContactName, ContactTitle, Address, City, Phone FROM (
    SELECT 
    ROW_NUMBER() OVER (ORDER BY {0} {1}) ROW,
    CompanyName, ContactName, ContactTitle, Address, City, Phone
    FROM Customers
) A where Row between {2} and {3}

2.添加一个NVelocity模板,用来获取我们想要的SQL语句

#set($result = $helper.createkeyvalueobject())
#set($result.rowsSql = $helper.readfilecontent("FlexiGrid_获取数据.sql", 
$sortname, $sortorder, $startIndex, $endIndex))
#set($result.totalSql = "SELECT COUNT(*) FROM Customers")
#set($result.id = "CompanyName")

3.前端调用

jQuery(document).ready(function () {
    var maiheight = document.documentElement.clientHeight;
    var w = jQuery("#ptable").width() - 3;
    var otherpm = 150; //GridHead,toolbar,footer,gridmargin
    var gh = maiheight - otherpm;

    var option = {
        height: gh, //flexigrid插件的高度,单位为px
        width: w,
        url: "WebService/CommonWebService.asmx/GetFlexiGridDataByTemplate",
        colModel: [
            { display: "公司名称", name: "CompanyName", width: 200, sortable: true },
            { display: "联系人名称", name: "ContactName", width: 120, sortable: true },
            { display: "标题", name: "ContactTitle", width: 150, sortable: false },
            { display: "地址", name: "Address", width: 250, sortable: true, hide: true },
            { display: "城市", name: "City", width: 100, sortable: true },
            { display: "电话", name: "Phone", width: 100, sortable: true }
        ],
        params: [
            { name: "templateFileName", value: "FlexiGrid_获取数据.htm" }
        ],
        buttons: [
              { name: "Add", displayname: "新增", onpress: toolbarItem_onclick },
              { name: "Delete", displayname: "删除", onpress: toolbarItem_onclick }
        ],
        sortname: "CompanyName",
        sortorder: "asc",
        title: "联系人列表",
        usepager: true,
        useRp: false,
        //rp: 5,
        rowbinddata: true,
        showcheckbox: true,
        rowhandler: rowEditHandler,
        selectedonclick: false,
        singleselected: true,
        //gridClass: "flexigrid"
        gridClass: "bbit-grid"
    };
    var grid = jQuery("#curtomerGrid").flexigrid(option);
});

怎么样,是不是很简单。最后让我们看看效果如何?

image

注:本文使用的Flexigrid为园友假正经哥哥修改过的版本,数据库使用的Northwind。

全部代码

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏