zoukankan      html  css  js  c++  java
  • Ajax服务端框架的综合示例

    本文将专门介绍:我的通用数据访问层 及 Ajax服务端框架的综合示例,同时也是为了让大家能对这二个组件有更多的了解。 因此,本文将以界面截图以及部分代码展示的方式来说明,这样可能会有更感性的认识它。

    这个演示网站的特点:
    1. 数据访问全使用了我的通用数据访问层 + 存储过程的实现。
    2. 页面使用了大量的Ajax技术,没有任何的直接提交或回传(Submit Form or postback),分页,查询,对话框,都以Ajax的方式实现。
    3. 所有Ajax技术的客户端全部基于JQuery,服务端则使用我的Ajax服务端框架
    4. 客户端UI使用JQuery Easy-UI
    5. 虽然没有使用Asp.net MVC框架,但却使用了MVC思想。

    运行环境需求:
    1. .net framework 3.5
    2. Sql Server 2005

    通用数据访问层 及 Ajax服务端框架 的技术特性:
    数据访问层设计目标 调用存储过程,不管输入参数多么复杂,不管有多少输出参数,包含转换一个结果集到实体列表,只需要一行C#代码。
    Ajax框架的特色 服务端中的C#方法或用户控件对于JS来说是透明的,就好像可以直接访问一下。
    Ajax框架的作用意义 接受JS的请求,去调用C#方法或者用户控件。
    至于如何调用方法,如何给方法的参数赋值,最后如何处理返回值给客户端,就属于框架本身的事情了。
    所有的这一切,对于客户端来说,更是透明的。这些透明的实现也就是框架的意义了。

    这个演示网站的业务原型来自于Northwind,但所有的表都是我重新根据示例需要而重新定义的, 数据来源于以前从网页上获取的数据,虽然不真实,但更适合于演示。于Northwind不同的是,为了示例, 所有的数据库操作全使用存储过程来完成。

    点击此处下载示例及文档。 (2011-11-26 最后更新)

    第一部分,界面截图

    主菜单

    基础数据包含三个部分,都比较类似,下图将展示“商品管理”页面

    上图中,表格最右边的列全是TextBox,可以直接修改,然后会以Ajax的方式提交到服务器。

    点击每条记录中的商品名称,将出现以下对话框,它用于新增或修改单个商品资料

    新增订单界面如下

    像很多C/S程序一样,“客户”可以从对话框中选择

    像很多C/S程序一样,“商品”也可以从对话框中选择

    数据全部录入后的样子如下图

    点击按钮“确定保存此订单记录 并继续新增”,表单将以Ajax方式提交给服务器。

    订单管理

    页面打开后,只有“查询条件”显示在页面上

    点击“查找订单”按钮,页面将以Ajax的方式向服务器发出请求,并将显示结果

    点击每行中的“订单编号”,将会出现下图

    示例程序还直接有“查看源代码”的功能哦

    调用数据访问层的代码

    /// <summary>
    /// 操作“商品记录”的业务逻辑层
    /// 为了简单演示,每个方法将打开一个连接。
    /// </summary>
    public sealed class ProductBLL 
    {
        public int Insert(Product product)
        {
            return FishBLLHelper.CallSpExecuteNonQuery("InsertProduct", product);
        }
    
        public int Delete(int productId)
        {
            return FishBLLHelper.CallSpExecuteNonQuery("DeleteProduct", null, productId);
        }
    
    
        public int Update(Product product)
        {
            return FishBLLHelper.CallSpExecuteNonQuery("UpdateProduct", product);
        }
    
    
        /// <summary>
        /// 获取指定的商品详细资料(加载所有字段)
        /// </summary>
        /// <param name="productId"></param>
        /// <returns></returns>
        public Product GetProductById(int productId)
        {
            return FishBLLHelper.CallSpGetDataItem<Product>("GetProductById", null, productId);
        }
    
        // 根据指定的分类ID,以及分页参数,获取商品记录列表
        public List<Product> GetProductByCategoryId(int categoryId, PagingInfo pagingInfo)
        {
            if( categoryId <= 0 ) {
                pagingInfo.RecCount = 0;
                return new List<Product>(0);
            }
    
            return FishBLLHelper.CallSpGetDataItemListPaged<Product>("GetProductByCategoryId", pagingInfo,     categoryId);
        }
    
    
        // 搜索商品
        public List<Product> SearchProduct(int categoryId, string searchWord, PagingInfo pagingInfo)
        {
            return FishBLLHelper.CallSpGetDataItemListPaged<Product>("SearchProduct", pagingInfo,    categoryId, searchWord);
        }
    
    
        /// <summary>
        /// 更新指定的商品数量
        /// </summary>
        /// <param name="productId"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        public int ChangeProductQuantity(int productId, int quantity)
        {
            return FishBLLHelper.CallSpExecuteNonQuery("ChangeProductQuantity", null, productId, quantity);
        }
    
    }
    
    /// <summary>
    /// 操作“订单记录”的业务逻辑层
    /// 为了简单演示,每个方法将打开一个连接。
    /// </summary>
    public sealed class OrderBLL : FishBaseBLL
    {
        /// <summary>
        /// 新增订单记录(包含订单明细)
        /// </summary>
        /// <param name="order"></param>
        /// <returns></returns>
        public int AddOrder(OrderItem order)
        {
            // 以事务的方式创建一个FishDbContext对象,将使用默认的连接字符串
            using( FishDbContext db = new FishDbContext(true) ) {
                // 添加记录到表Orders,同时获取新产生ID
                FishBLLHelper.CallSpExecuteNonQuery(db, "InsertOrder", order);
                
                // 为订单明细设置OrderId,并添加到表[Order Details]
                order.Detail.ForEach(x => {
                    x.OrderID = order.OrderID;
                    FishBLLHelper.CallSpExecuteNonQuery(db, "InsertOrderDetail", x);
                });
    
                // 刷新订单总金额。
                FishBLLHelper.CallSpExecuteNonQuery(db, "RefreshOrderSumMoney", null, order.OrderID);
    
                // 提交事务。
                db.CommitTransaction();
    
                return order.OrderID;
            }
        }
    
    
        // 根据指定的查询日期范围及分页参数,获取订单记录列表
        public List<OrderItem> Search(object dateRange, PagingInfo pagingInfo)
        {
            // 按分页的方式查询数据库。关于分页的查询方式请参见:CustomerBLL.GetList()
            return FishBLLHelper.CallSpGetDataItemListPaged2<OrderItem>("SearchOrder", pagingInfo, dateRange);
        }
    
        /// <summary>
        /// 根据订单ID获取订单相关的所有信息
        /// </summary>
        /// <param name="orderId"></param>
        /// <returns></returns>
        public OrderItem GetOrderById(int orderId)
        {
            // 以非事务的方式创建一个FishDbContext对象,将使用默认的连接字符串
            // 如果一次只调用一个存储过程,则不需要创建FishDbContext对象,在调用FishBLLHelper的方法时,会自动创建(使用默认的连接字符串)
            // 这里“显式”的创建FishDbContext对象是为了让二个存储过程在一个连接内完成调用。
            using( FishDbContext db = new FishDbContext(false) ) {
                OrderItem order = FishBLLHelper.CallSpGetDataItem<OrderItem>(db, "GetOrderById", null, orderId);
                if( order != null ) 
                    order.Detail = FishBLLHelper.CallSpGetDataItemList<OrderDetail>(db, "GetOrderDetails", null, orderId);
    
                return order;
            }
        }
    
        /// <summary>
        /// 修改指定的订单状态
        /// </summary>
        /// <param name="orderId"></param>
        /// <param name="finished"></param>
        /// <returns></returns>
        public int SetOrderStatus(int orderId, bool finished)
        {
            return FishBLLHelper.CallSpExecuteNonQuery("SetOrderStatus", null, orderId, finished);
        }
    }
    
    

    Ajax演示代码

    新增订单,JS 代码

    function btnSubmit_click() {
        if( $("#hfProductIdList").val().length == 0 ){
            $.messager.alert(g_MsgBoxTitle, "没有明细项目不能保存。", "warning"); return false;
        }
        
        // 获取订单明细项目,组合成一个字符串,格式:id=quantity;
        var detail = '';
        $("#tblOrderDetail input[name^=quantity_]").each(function(){
            detail += $(this).attr("name").substring(9) + "=" + $(this).val() + ";";
        });
        $("#hfOrderDetail").val(detail);
         
        // 向服务器提交表单。注意URL参数。
        var j_dialog = ShowWaitMessageDialog();
        $("form").ajaxSubmit({ url: "/AjaxOrder.AddOrder.cs",
            complete: function() { HideWaitMessageDialog(j_dialog); },
            success: function(responseText, statusText) {
                if (responseText == "1")
                    $.messager.alert(g_MsgBoxTitle, "操作成功", "info", function(){ window.location = window.location; });
                else
                    $.messager.alert(g_MsgBoxTitle, "提交失败,错误消息或代码:<br />" + responseText ,'error');
            }
        });
        return false;
    }
    

    新增订单,C# 代码

    /// <summary>
    /// Ajax服务类,提供“订单记录”相关操作
    /// </summary>
    public static class AjaxOrder
    {
        //--------------------------------------------------------------
        // 注意: 
        //     用于Ajax的类,可以是静态的,方法也可以是静态的。
        //--------------------------------------------------------------
    
        /// <summary>
        /// 新增订单
        /// </summary>
        /// <param name="form"></param>
        /// <returns></returns>
        public static int AddOrder(OrderSubmitForm form)
        {
            OrderItem order = form.ConvertToOrderItem();
            int newOrderId = BllFactory.GetOrderBLL().AddOrder(order);
            return (newOrderId > 0 ? 1 : 0);
        }
    }
    
    
    public sealed class OrderSubmitForm : MyDataItem
    {
        public DateTime OrderDate;
        public int CustomerID;
        public string OrderDetail;
        public string Comment;
    }
    

    显示订单明细对话框,JS 代码

    function ShowOrderDialog(){
        var dom = this;
        var orderId = $(this).attr("OrderNo");
        var url = "/AjaxOrder.Show.cs?id=" + orderId;
        ShowViewerDialog("divOrderInfo", url, function(){
            $("#tblOrderDetail").SetGridStyle().find("a.easyui-linkbutton").linkbutton().click(ShowProductDialog);
            $("#btnSetOrderStatus").linkbutton().click(function(){    SubmitSetOrderStatus( orderId, dom ); return false; });
        }, 800, 530);
        return false;
    }
    

    显示订单明细对话框,C# 代码

    public static class AjaxOrder
    {
        public static string Show(int id)
        {
            if( id <= 0 )
                throw new MyMessageException("没有指定OrderId");
    
            OrderItem item = BllFactory.GetOrderBLL().GetOrderById(id);
            if( item == null )
                throw new MyMessageException("指定的ID值无效。不能找到对应的记录。");
    
            // 执行用户控件,并返回生成的HTML代码,用户控件呈现所需要的数据通过第二个参数传递。
            return FishWebLib.Ajax.UcExecutor.Execute("~/Controls/OrderInfo.ascx", item);
        }
    }
    
    public sealed class OrderItem : MyDataItem
    {
        public int OrderID { get; set; }
        public int? CustomerID { get; set; }
        public DateTime OrderDate { get; set; }
        public decimal SumMoney { get; set; }
        public string Comment { get; set; }
        public bool Finished { get; set; }
        public string CustomerName { get; set; }
    
    
        public List<OrderDetail> Detail;
    }
    

    OrderInfo.ascx代码如下(并没有与之对应的cs代码哦,关于这个,以后再谈)

    <%@ Control Language="C#" Inherits="FishWebLib.Mvc.MyUserControlView<OrderItem>" %>
    
    <table cellpadding="4" cellspacing="0" style="width: 99%">
    <tr><td style="width: 60px">订单日期</td><td>
        <input type="text" class="myTextbox" readonly="readonly" style="width: 200px" 
    			value="<%= Model.OrderDate.ToString("yyyy-MM-dd HH:mm:ss") %>" />
        </td></tr>
    <tr><td>客户</td><td>
        <input type="text" class="myTextbox" readonly="readonly" style="width: 400px" 
    			value="<%= Model.CustomerName.HtmlEncode() %>" />
        </td></tr>
    <tr><td class="vertical">订单明细</td><td>
        <table cellpadding="4" cellspacing="0"  id="tblOrderDetail" class="GridView">
            <tr>
                <td style="width: 450px">商品名称</td>
                <td style="width: 60px">单位</td>
                <td style="width: 60px">数量</td>
                <td style="width: 60px">单价</td>
            </tr>        
    <% foreach( var item in Model.Detail ) { %>
    <tr>
        <td><a href="#" ProductId="<%= item.ProductID %>" class="easyui-linkbutton" plain="true">
    			<%= item.ProductName.HtmlEncode() %></a></td>
        <td><%= item.Unit.HtmlEncode()%></td>
        <td><%= item.Quantity %></td>
        <td><%= item.UnitPrice.ToString("F2") %></td>
    </tr>
    <% } %>
            <tr><td colspan="4" style="text-align: right; padding-right: 10px;">
                订单总金额:<b><%= Model.SumMoney.ToText() %></b>
            </td></tr>        
        </table>
    </td></tr>
    
    <tr><td class="vertical">备注</td><td>
        <textarea class="myTextbox" style="width: 660px; height: 70px" readonly="readonly" >
    			<%= Model.Comment.HtmlEncode()%></textarea>
        </td></tr>
    <tr><td></td><td>
        <label><%= Model.Finished.ToCheckBox("chkFinished", null, false) %>订单已处理</label>    &nbsp;&nbsp;&nbsp;
            <a id="btnSetOrderStatus" href="#" class="easyui-linkbutton" iconCls="icon-ok">修改订单状态</a>        
        </td></tr>
    </table>
    
    

    组件性能测试

    我在写这二个组件时,就很关心性能问题,因此特意写了二个性能的测试项目。

    本演示程序的压缩包解开后,其中有二个目录(TestAjaxPerformance 和 TestDALPerformance)分别是测试数据访问层和Ajax框架性能的。

    TestDALPerformance是用于测试数据访问层的项目,对比的对象是“手工代码方式”和Linq to SQL, EF框架

    TestAjaxPerformance是用于测试Ajax框架性能的项目,对比的对象是Asp.net MVC 2

    我自己在我的笔记本上测试过,比微软的同类框架要快。不信您可以自己去运行起来看一下。

    用户手册,API文档

    为了简单,贴图算了。

    点击此处下载示例及文档。 (2011-11-26 最后更新)

  • 相关阅读:
    项目计划进度控制与资源管理
    读大道至简所思
    Java自学第三十二天
    Java自学第三十一天
    Java自学第三十天
    Java自学第二十九天
    Java自学第二十八天
    Java自学第二十七天
    Java自学第二十六天
    Java自学第二十五天
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2294204.html
Copyright © 2011-2022 走看看