好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

深入剖析Web分页原理

深入剖析Web分页原理

说一下今天天气很好,心情也非常的不错,写起来也非常舒畅,也希望园友们每天好心情,为自己的人生目标努力着!

  这段时间因为项目需要,要做一个分页的功能,说实话这类的文章在园子里面可以说是满天飞了,为什么要写呢?没什么高深的技术,只是做个总结,把那些零零碎碎的问题整合起来,好给大家一个完整的参考吧!

  这是我第一次自动动手写分页,所以这样的文章适合跟我一样的小菜阅读....

  1.分页的最基本参数                            

?

总页数                   →  PageTotalCount                         //查询的结果分页之后有多少页

总记录数                 →  RecordTotalCount                       //查询的结果包含多少条记录

每一页的记录数            →  DisplayRecordCount                     //每一页显示多少条记录数

一次显示多少页数         →  DisplayPageCount                       //一次加载显示多少个页数,五个或者十个等等

首页和末页                →  FirstPage ,LastPage                   //快速回到第一页以及最后一页的按钮

上一页和下一页            →  UpPage,NextPage                       //下一页和上一页

页索引号                → IndexPage                             //用户当前点击的页号码

  Note:这只是最基本的参数,还有很多的查询参数需要我们按照自己的项目需求来定义!

   Note: 对于总记录数的获取我的方案是使用输出参数来获取!

   

  2.在URL地址中传入分页参数实现分页              

    2.1 原理 :

      主要是通过获取URL中的参数值来判断用户点击的是第几页!

    2.2 机制 :

      通过查看HTML代码,发现每一个分页按钮的超链接都是这样写的,如:    

    

    博客园分页源代码:

    所以这种的方式还是比较常用的!

    2.3 原理分析 :

             ①所有的HTML的代码在后台进行组装,然后在页面加载的时候进行输出!

             ②每个超链接的href属性都在后台进行赋值!

             ③对一些复杂的业务逻辑进行有效处理!

    2.4 解决点击“...”按钮的问题,说实话这里面的逻辑还是有点复杂的,我搞了好久才弄清楚了 :    

    

      这边涉及到一个层的概念(不是标准术语),所谓的层就是一个页面一次性显示的的总页数!    

       Note :      层的层次关系:

                              1,2,3 … 10;              第一层   索引号为“0”

                              11,12,13 … 20;        第二层              “1”

                              21,22,23 … 30;        第三层              “2”    

       如果说你的总页数有98页,每一次显示10页,那么分页的总层数就为 → int pageLevelCount =  98 % 10 ==0 ? 98 / 10 : 98 / 10 + 1

       有如下几个核心代码:     

 1         int  currentPageLevel = pageIndex /  10 ;         //  当前页所在的层数
 2         //  过滤一下整数,如10,20,30 本来他们应该属于自己的层数,但是通过上面的计算会增加一个层数,所以要过滤下  
3 currentPageLevel = pageIndex % 10 == 0 ? currentPageLevel - 1 : currentPageLevel;

4 int pageTotalLevelCount = pageTotalCount / 10 ; // 总层数,如果不是10的倍数,就会少一层,主要用于后面“…”做判断的
 5         //  计算后面三个点“...”处于什么样的页索引号,如果当前页+1 乘以10大于总页数,那么说明后面没有了!
6        //下面的变量 判断当前的页层数是不是最后一个页层数!
7 int currentPageLastLevel = 10 * (currentPageLevel + 1 ) > pageTotalCount ? pageTotalCount : 10 * (currentPageLevel + 1 );

复制代码

       下面的代码是判断页面上时候有“...”的按钮:   

  1           //  对前面“...”按钮的判断  
2          if (pageIndex > 10 ) // 对也按钮的设置
3 {
4 strBuilder.AppendFormat(GetAHtml( "" , string .Format(url, 10 * pagecount), " ... " ));
5 }
6          // 后面显示“...”按钮的判断
7         if (pageIndex <= 10 * floorcount) // 当当前序号小于倒数第二页页码时显示在后端...
8 {
9 strBuilder.AppendFormat(GetAHtml( "" , string .Format(url, 10 * (pagecount + 1 ) + 1 ), "" ));
10 }    

复制代码

       如果能够把这些逻辑搞清楚了,分页也就不算太难了!

   下面是全部代码:   

?

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Data.SqlClient;

using System.Data;

using System.Text.RegularExpressions;

using System.Text;

 

namespace Web分页原理学习Demo

{

     public partial class _Default : System.Web.UI.Page

     {

         public int totalCount = 0;

         public int pageIndex = 1;

         public string pageHTML = "" ;

         string url = HttpContext.Current.Request.Url.AbsoluteUri; //当前页面绝对路径

         protected void Page_Load( object sender, EventArgs e)

         {

             string QueryStringName = Request.QueryString[ "page" ];

             //QueryStringName = QueryStringName == null ? "1" : QueryStringName;

             //首先先获取URL

             //" http://localhost:1033/Default.aspx "

 

             pageIndex = QueryStringName == null ? 1 : Convert.ToInt32(QueryStringName);

 

             //对URL进行一些设置

             if (url.Contains( "aspx?" ))

             {

                 if (Regex.IsMatch(url, @"page=[0-9]*$" , RegexOptions.IgnoreCase)) //如果存在page=*的字符串

                 {

                     url = Regex.Replace(url, @"page=[0-9]*$" , "" , RegexOptions.IgnoreCase); //替换掉page=*的字符串

                 }

                 url += "page" + "={0}" ;

             }

             else

             {

                 url += "?" + "page" + "={0}" ;

             }

             //if (!url.Contains("page"))

             //{

             //    url += "?page={0}";

             //}

 

             this .Repeater1.DataSource = GetData(pageIndex);

             this .Repeater1.DataBind();

 

             pageHTML = GetPageHTML(totalCount, pageIndex, url);

         }

 

         public DataTable GetData( int pageIndex)

         {

             DataTable dt = new DataTable();

             string connString = @"server=22610800E100468;integrated security = SSPI;database=Northwind" ;

             using (SqlConnection conn = new SqlConnection(connString))

             {

                 SqlCommand cmd = conn.CreateCommand();

                 cmd.CommandText = "MyPage" ;

                 cmd.Parameters.Add( new SqlParameter( "@pageIndex" , pageIndex));

                 SqlParameter para = new SqlParameter();

                 para.ParameterName = "@recordTotalCount" ;

                 para.DbType = DbType.Int32;   //必须指明参数类型

                 para.Direction = ParameterDirection.Output;

                 cmd.Parameters.Add(para);

                 cmd.CommandType = System.Data.CommandType.StoredProcedure;

                 SqlDataAdapter da = new SqlDataAdapter(cmd);

                 da.Fill(dt);

 

                 totalCount = ( int )da.SelectCommand.Parameters[ "@recordTotalCount" ].Value;

             }

 

             return dt;

         }

 

         //开始填充HTML代码

         public string GetPageHTML( int recordTotalCount, int pageIndex, string url)

         {

             StringBuilder strBuilder = new StringBuilder(1000);

             string attr = "" ;

             int pagecount = 0; //当前页面的总层数

             int floorcount = 0; //分页的总层数

             int currentLastPage = 0; //当前最后一页的页码,用来保存最后一页的号码

 

             //总页数

             int pageTotalCount = recordTotalCount / 10 + 1;

             strBuilder.Append( "<div>" );

             attr = pageIndex == 1 ? "visible=\"" + "false\"" : "" ; //标志当前页第一页是否相等 来控制前俩个按钮的有效性

             strBuilder.AppendFormat(GetAHtml(attr, string .Format(url, 1), "首页" ));

             strBuilder.AppendFormat(GetAHtml(attr, string .Format(url, pageIndex - 1), "上一页" ));

 

             pagecount = pageIndex / 10; //当前页数 0~1~2

             pagecount = pageIndex % 10 == 0 ? pagecount - 1 : pagecount; //清除当 当前页数为分页页码数的整数倍页时除数多一的状况

             floorcount = pageTotalCount / 10; //页面层数 0~1~2

             currentLastPage = pageTotalCount < 10 * (pagecount + 1) ? pageTotalCount : 10 * (pagecount + 1);

 

             if (pageIndex > 10)  //对也按钮的设置

             {

                 strBuilder.AppendFormat(GetAHtml( "" , string .Format(url, 10 * pagecount), "..." ));

             }

             for ( int i = 10 * pagecount + 1; i < currentLastPage; i++)

             {

                 if (i == pageIndex)

                 {

                     strBuilder.AppendFormat(GetSpanHtml(i, "" ));

                 }

                 else

                 {

                     strBuilder.AppendFormat(GetAHtml( "" , string .Format(url, i), i.ToString())); //设置超链接

                 }

             }

             if (pageIndex <= 10 * floorcount) //当当前序号小于倒数第二页页码时显示在后端...

             {

                 strBuilder.AppendFormat(GetAHtml( "" , string .Format(url, 10 * (pagecount + 1) + 1), "" ));

             }

 

             attr = pageIndex == pageTotalCount ? "visible=\"" + "false\"" : "" ; //标志当前页最后一页是否相等 来控制后俩个按钮的有效性

             strBuilder.AppendFormat(GetAHtml(attr, string .Format(url, pageIndex + 1), "下一页" ));

             strBuilder.AppendFormat(GetAHtml(attr, string .Format(url, pageTotalCount), "末页" ));

 

             strBuilder.AppendFormat( "</div>" );

 

             return strBuilder.ToString();

         }

 

         /// <summary>

         /// get the html of a label

         /// </summary>

         /// <param name="title">a's title</param>

         /// <param name="url">the url of a</param>

         /// <param name="attr">the attribute</param>

         /// <returns>return html string</returns>

         private static string GetAHtml( string attr, string url, string title)

         {

             return "<a " + attr + " href=\"" + url + "\" style=\"margin-right:5px;\">" + title + "</a>\n" ;

         }

 

        //这个方法的目的是固定住当前用户点击的页索引

         private static string GetSpanHtml( int num, string className)

         {

             return "<span class=\"" + className + "\">" + num + "</span>\n" ;

         }

     }

}

  

   3.分页存储过程深入学习                        

    3.1 定义表变量来存储数据,实现分页      

   --  使用表变量来读取数据,注意表变量的语法,定义一个自动那个增长列用来以后的分页  
DECLARE @MyTable TABLE (myID INT IDENTITY ( 1 , 1 ),OrderID INT ,CustomerID NCHAR ( 5 ))
-- 把你删选的数据填充到表变量中去
INSERT INTO @MyTable (OrderID,CustomerID)
(
SELECT OrderID,CustomerID FROM dbo.Orders
)
SELECT myID,OrderID,CustomerID FROM @MyTable WHERE myID BETWEEN 1 AND 10

复制代码

       Note:自SQL Server2005之后出来了“ CTE ”的语法,大家也可以使用这种方式来进行分页! 

 1     WITH  MyTable(ID, Number )
2    AS
3   (
4    SELECT AppID,ROW_NUMBER() OVER ( ORDER BY AppID) FROM Core
5   )
6
7    SELECT * FROM MyTable WHERE Number BETWEEN 10000 AND 10010

复制代码

      3.2 使用“Top”和“In”      

 1      --  使用“TOP”跟“IN”语法  
2 SELECT TOP 10 OrderID FROM dbo.Orders WHERE OrderID NOT IN
3 (
4 SELECT TOP 10 OrderID FROM dbo.Orders
5 )
6 // 这个语句就可以查处表中第“ 11 ”条到“ 20 ”的数据了!

复制代码

   

      3.3 使用“Row_Number() Over(Order By [字段名] DESC)”

 1      --  这是SQL Server2005新出来的函数,不仅操作简单,而且还易于理解!  
2 -- 所以了解这个函数的语法就变得很重要了!
3    SELECT OrderID,CustomerID FROM
4   (
5    SELECT OrderID,CustomerID, ROW_NUMBER() OVER ( ORDER BY OrderID) AS number FROM dbo.Orders
6   ) AS T
7    WHERE T. number BETWEEN 1 AND 10

复制代码

     Note :你可以指定你要排序的主键是按升序还是按降序排列!ASC → 升序,DESC → 降序!


     3.4 使用“Top”和“Max”

  1      --  分页思想:  
2 -- 首先根据主键进行排序,删选出前十条,默认是降序排列
3 -- 然后取出前十条的最大值,也就是前十条的最后一条记录
4 -- 最后在删选出这条记录的后十条记录,那么就是“11”到第“20”条的记录了
5 SELECT TOP 10 OrderID,CustomerID FROM dbo.Orders AS T WHERE T.OrderID >
6 (
7 SELECT MAX (TempTable.OrderID) FROM
8 ( SELECT TOP 10 OrderID FROM dbo.Orders ORDER BY OrderID) AS TempTable
9 )
10 // 默认为升序 → ASC

复制代码

      3.5 分页查询速度比较

      说实话这些比较园子里面也很多,我就做个总结了,不实际测试了!

       Top,Max  >  Row_Number  >  Top  >  表变量 !

   

    3.6 比较“Top Max”和“Row Number”的性能差异所在

      如果对“SQL 执行计划”还没有一定的理解,请先看这篇文章: 看懂SqlServer查询计划  ,值得一看的文章!      

      

      从上面的可以看出,在单表分页的情况下,“Row_Number”比“Top ,Max”会多检索出很多行,那么在性能上“Top Max”就比“Row_Number”好点!

      Note:这种情况只限于单表操作的情况下,如果说是多表查询,感觉还是用“Row_Number”会比较好点,因为在多表的情况下,“Top,Max”或做出两次的连接查询,在大数据量的情况下,性能会比“Row_Number”差一点!如图:      

      

  4.大数据的分页思想                          

    前几天看到一片文章是说关于百度,Google他们的分页思想,找不到那篇文章了,找到了园友发个链接给我!

    我也是看到这些文章做个小总结,没什么创新!    

每一张表设置固定的容量,达到一定程度后,把新纪录转移到另外一张表中,让以前的那些表成为历史数据! 做好查询需要的索引,虽然不能滥用索引,但是适当的增加将加快查询速度! 优化查询,避免表扫描,少用模糊查询,也就是在没有索引的前提下,扫描整张表! 在服务端代码中尽量考虑到数据缓冲和连接池的情况! 对于千万级的数据,可以参考百度,Goole等网站的分页技巧! 其实它们的分页利用了客户只关注前面重要的信息,越往后就不会太多的关注的思维定势! 千万级的数据,只取出前面几十万的信息,然后进行排序分页!  

  

  5.思路很重要                             

  我总觉得在编程之前应该就把思路理清楚,清楚之后就能行如流水,但是现在的我还没有到达这个境界,需要多多努力!

  好了,差不多就是这么多了,也算对分页有了一点点的理解了,不至于以后工作需要而手忙脚乱的,写在这边与大家一起分享! 

[02] 学习的那些事

在学习中深入,在实践中提高

学习之路九:深入剖析Web分页原理

posted @  2012-03-24 17:26  程序猿就是我 阅读(1117) |  评论 (5)   编辑

 

学习之路八:解决不能调试服务端代码的问题

posted @  2012-03-16 18:28  程序猿就是我 阅读(60) |  评论 (1)   编辑

 

学习之路七:一步一步学习ASP.NET数据绑定

posted @  2012-03-12 19:02  程序猿就是我 阅读(1648) |  评论 (8)   编辑

 

学习之路六:奇怪的DataTime转换以及格式化问题

posted @  2012-03-01 18:54  程序猿就是我 阅读(1222) |  评论 (2)   编辑

 

学习之路五:再议自定义时钟类(跨线程间的访问操作) → 异步操作

posted @  2012-02-18 19:42  程序猿就是我 阅读(1011) |  评论 (1)   编辑

 

学习之路四:各种异步操作我也来山寨一下 → 思维导图

posted @  2012-01-10 17:39  程序猿就是我 阅读(163) |  评论 (1)   编辑

 

学习之路三:关于运用单线程和委托以及事件自定义Timer类

posted @  2011-12-31 14:33  程序猿就是我 阅读(1006) |  评论 (7)   编辑

 

学习之路二:关于集合和数组内在联系的深入了解

posted @  2011-12-23 20:10  程序猿就是我 阅读(1128) |  评论 (6)   编辑

 

学习之路一:关于使用微软的COM组建操作Excel的那些事

posted @  2011-12-17 19:52  程序猿就是我 阅读(1288) |  评论 (13)   编辑


作者: Leo_wl

    

出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于深入剖析Web分页原理的详细内容...

  阅读:50次