开发客户端的人员(在理论条件下)可以完全忽略服务端的语言种类,只进行纯Javascript开发,利用JQUERY中提供的AJAX方法同服务端方法通信。

从上面的整体架构图,我们看出:其客户端都是WebService接口来获取数据和传送数据的,而服务端业务模型是什么语言开发的,完全不需要关注(当然在现实情况下,一般WebService接口最好同服务端业务模型是一个语言开发的)。
这个时候可以会首先想到效率的问题:
众所周知,WebService接口的效率较慢,那么这样搞是不是会让采用这种结构模型开发的网站速度变慢,与其这样,还不如采用常规的方法开发,不仅熟悉而且速度也不错呢?
先看下面几个推论:
1)WebService接口的效率慢 <---> 异步获取数据 ,两者互相能够抵消吗?
2)客户端采用Post的方式,可以减少数据的量,能部分抵消WebService接口的效率慢吗?
以上两个推论,虽然我们没完全做过对比,但可以肯定的说,它们是有对冲效率的,WebService慢,反映在页面端无怪乎就是页面等待长时间不出来,造成用户体验下降,但因为采用异步获取的方式,这种情况还会出现吗?应该不会。
在传送过程中,采用Post方式,数据量大大减少,又采用了异步方式,实际运行效果应该是相当不错的。
但对于某些特殊情况并且有很普遍的问题,比如Table表格的分页情况,我们又该怎么处理呢?
Table表格数据填充和分页 这个在页面上非常普遍的问题确对以上的推论造成了威胁,究其原因就是因为一般的分页代码都是把数据返回到客户端内存中,然后进行分页,因此大量的数据从服务端传递到客户端,必然造成问题,其实这个问题不仅仅是这个框架的问题,所有采用这种方式进行分页的代码都存在这样的问题,只不过这个框架采用WebService接口与客户端通信,才导致这个问题的重要性被无限放大了。
以下我们就来讨论在这种框架下进行分页的处理:
环境:Visual studio 2005
JQuery 1.3.2
SQLServer2005
分页原理:

从上图中,看到不管数据表中有多少数据,每次返回到客户端的数据都是一页的数据,这种方法没有采用存储过程方式,而是在webservice端进行处理的。
代码片段:
服务端填充Table表格代码----:
说明:
TB_WEB_NZ_INVESTMENT 是实体类,对应表对象
FlowID 表对象的字段属性,通过它获取一类相似的数据记录
代码中有对【首页】,【尾页】,【中间页】的元素进行过滤,对返回的泛型List对象进行范围过滤
- /// <summary>
- /// 分页功能的表格填充服务端
- /// </summary>
- /// <param name="FlowID"></param>
- /// <param name="PageCount">每页数目</param>
- /// <param name="CurrentPage">当前页</param>
- /// <returns></returns>
- [WebMethod]
- [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
- public string Load_ContributivePerson_Table(string FlowID, int PageCount, int CurrentPage)
- {
- List<TB_WEB_NZ_INVESTMENT> list = new List<TB_WEB_NZ_INVESTMENT>();
- list = objBusinessFacade.GetTB_WEB_NZ_INVESTMENT_CollectionByFlowID(FlowID);
- int TotalPageCount = 0;
- if (PageCount != 0)
- {
- if ((list.Count % PageCount) > 0)
- {
- TotalPageCount = list.Count / PageCount + 1;
- }
- else
- {
- TotalPageCount = list.Count / PageCount;
- }
- }//if
- if (CurrentPage == 1)
- {
- //第一页
- if (PageCount < list.Count)
- {
- list.RemoveRange(PageCount, list.Count - PageCount);
- }
- }
- else if (CurrentPage > 1 && CurrentPage < TotalPageCount)
- {
- //中间页
- int R1 = (CurrentPage - 1) * PageCount-1;
- int R2 = CurrentPage * PageCount;
- List<TB_WEB_NZ_INVESTMENT> list1 = new List<TB_WEB_NZ_INVESTMENT>();
- for (int i = 0; i < list.Count; i++)
- {
- if (i > R1&&i<R2)
- {
- list1.Add(list[i]);
- }
- }
- list.Clear();
- list = list1;
- }
- else if (CurrentPage == TotalPageCount)
- {
- //尾页
- //但返回的显示对象列表确只能是最后一页里面的记录
- //这里需要剔除不是最后一页的元素对象
- list.RemoveRange(0,(CurrentPage-1) * PageCount);
- }
- return new JavaScriptSerializer().Serialize(list);
- }
原理说明图:-----------------------
结合以上代码和该图讲解:
1)首页操作:
list.RemoveRange(PageCount, list.Count - PageCount);
翻译成数字:list.RemoveRange(5,14-5);
首页显示的元素:A1 A2 A3 A4 A5 对应的索引:0 1 2 3 4
list.RemoveRange(5,14-5); //排除索引值为5(含自身)的后面的所有元素,这样列表中只有A1-A5 元素
2)中间页操作:(这里就是第2页)
- List<TB_WEB_NZ_INVESTMENT> list1 = new List<TB_WEB_NZ_INVESTMENT>();
- for (int i = 0; i < list.Count; i++)
- {
- if (i > R1&&i<R2)
- {
- list1.Add(list[i]);
- }
- }
- list.Clear();
- list = list1;
3)尾页操作:
- //尾页
- //但返回的显示对象列表确只能是最后一页里面的记录
- //这里需要剔除不是最后一页的元素对象
- list.RemoveRange(0,(CurrentPage-1) * PageCount);
尾页的代码就简单一些。
从以上的服务端代码,我们看出虽然每次从数据库返回全部的代码到webservice端,但通过这个方法,就将其无用的记录全部过滤了,把剩下的元素传递到客服端,这样不管记录有多少条,每次返回页面的都只有一点点,提高了效率,避免了webservice传递大数据的问题,这样这个框架在传递大数据的方面基本不存在任何问题(排除一些及其特殊的东西),运用这个框架在效率方面不存在任何问题,甚至比普通的页面还要快。
客户端代码片段:
客户端就不再详细说明了,客户端需要传入
PageCount 每页显示的记录数
CurrentPage 当前页数
表格的html:
- <table id="TData" width="100%" >
- <thead id="thead">
- <tr id="TR_Header" class="MyTableTR_Header" align="center" style=" height:25px">
- <td style="width:1%; display:none" class="MyTableTD"></td>
- <td style="width:10%" >投资人类型</td>
- <td style="width:10%">投资人</td>
- <td style="width:10%">出资方式</td>
- <td style="width:10%">认缴出资额</td>
- <td style="width:10%">实缴出资额</td>
- <td style="width:10%">出资比例</td>
- <td style="width:15%">余额缴付期限</td>
- <td style="width:15%">资料是否完整</td>
- <td style="width:10%">操作</td>
- </tr>
- </thead>
- <tbody id="tbody_Data"></tbody>
- <tfoot id="tfoot_foot">
- <tr align="right">
- <td style="width:100%" colspan="9">
- <a href="#" id="First_A">首页</a>
- <a href="#" id="Prev_A">上一页</a>
- <a href="#" id="Next_A">下一页</a>
- <a href="#" id="Last_A">尾页</a>
- 跳到<input id="ToPageNo" type="text" style="width:20px; height:10px; font-size:9px"/>页 |
- 总页数:<span id="showTotalPage" style="color:Red"></span>页
- </td>
- </tr>
- </tfoot>
- </table>
填充数据的js函数:
- //引导数据填充表格(Table)
- function Load_TableData(FlowID,CurrentPage)
- {
- $.ajax({
- type: "POST",
- url: IPServer +"JsonService.asmx/Load_ContributivePerson_Table",
- data:"{FlowID:'"+FlowID+"',PageCount:"+PageCount+",CurrentPage:" + CurrentPage +"}" ,
- contentType: "application/json; charset=utf-8",
- dataType: "json",
- success: function(msg){
- msg = msg.replace(new RegExp('(^|[^\\\\])\\"\\\\/Date\\((-?[0-9]+)\\)\\\\/\\"', 'g'), "$1new Date($2)");
- var data = eval("(" + msg + ")");
- var strTR="";
- var RowCount = 1;
- jQuery.each(data, function(rec) {
- strTR += "<TR id='TR_" + RowCount + "' class='MyTableTR' align='center' >";
- strTR += " <TD style='width:1%; display:none' id='Key_"+RowCount+"' class='MyTableTD' >" + this.INVID + "</TD>";
- strTR += " <TD style='width:10%' class='MyTableTD' >" + this.INVTYPEName + "</TD>";
- strTR += " <TD style='width:10%' class='MyTableTD' >" + this.INV + "</TD>";
- strTR += " <TD style='width:10%' class='MyTableTD' >" + this.CONFORM + "</TD>";
- strTR += " <TD style='width:10%' class='MyTableTD' >" + this.SUBCONAM + "</TD>";
- strTR += " <TD style='width:10%' class='MyTableTD' >" + this.ACCONAM + "</TD>";
- strTR += " <TD style='width:10%' class='MyTableTD' >" + this.CONPROP + "</TD>";
- strTR += " <TD style='width:15%' class='MyTableTD' >" + this.BALDEPER_ShortString + "</TD>";
- strTR += " <TD style='width:15%' class='MyTableTD' >" + this.IsDataCompleteness + "</TD>";
- strTR += " <TD style='width:10%' class='MyTableTD' ><a id='Link_"+RowCount+"' href='#' >选择</a></TD>";
- strTR += "</TR>";
- RowCount++;
- });//jQuery.each
- $("#tbody_Data").empty();
- $("#tbody_Data").append(strTR);
- $("#CurrentPage").html(CurrentPage);
- },
- error:function(msg){
- alert( "Error: " + msg );
- }
- });
- }//function Load_TableData()
首页,上一页,下一页,尾页的操作:
说明:
$("#CurrentPage").html() 存储当前页 (调用代码在上个函数红色处)
$("#TotalPageCount").html() 存储总页数 (调用代码有个专门的函数,见下面)
- $("#First_A").click(function(){//首页 链接操作
- Load_TableData(strFlowID,1);
- });
- $("#Prev_A").click(function(){//上一页 链接操作
- var intCurrentPage = Number(c);
- if(intCurrentPage>1)
- {
- Load_TableData(strFlowID,intCurrentPage-1);
- }
- });
- $("#Next_A").click(function(){//下一页 链接操作
- var intCurrentPage = Number($("#CurrentPage").html());
- var intTotalPageCount = Number($("#TotalPageCount").html());
- if(intCurrentPage<intTotalPageCount)
- {
- Load_TableData(strFlowID,intCurrentPage+1);
- }
- });
- $("#Last_A").click(function(){//尾页 链接操作
- intLastPage = Number($("#TotalPageCount").html());
- Load_TableData(strFlowID,intLastPage);
- });
返回总页数的客户端函数:
- //返回页数
- function Get_TableData_TotalCount(FlowID)
- {
- $.ajax({
- type: "POST",
- url: IPServer +"JsonService.asmx/Get_ContributivePersonTable_TotalPageCount",
- data:"{FlowID:'"+FlowID +"',PageCount:"+PageCount+"}" ,
- contentType: "application/json; charset=utf-8",
- dataType: "json",
- success: function(msg){
- var data = eval("(" + msg + ")");
- jQuery.each(data, function(rec) {
- $("#TotalPageCount").html(this.Info);
- $("#showTotalPage").html(this.Info);
- });//jQuery.each
- },
- error:function(msg){
- alert( "Error: " + msg );
- }
- });
- }
- <div id="CurrentPage" ></div>
- <div id="TotalPageCount" ></div>
最后效果图:

总结:
Table数据填充并分页还有很多方法,这里只是提供了一种通过服务端就进行过滤的方法,让其返回客户端的数据始终就一点,提高了效率。