详谈javaWeb分页的实现(模拟百度分页)

本文出自 http://blog.csdn.net/tjpu_lin/article/details/41050475

最近在开发一个项目,项目中有很多数据展示的模块,所以要用到分页,网上搜了很多分页的例子,但是很多实现的方法和自身的代码实例耦合度太高,导致直接拿来用根本不行。

于是自己只能亲自上阵了,关于分页实现大体逻辑是前台需要和后台相互传递页面参数(例如当前页面,页面大小,总共页数等),后台主要接受前台穿过来的pageNum(当前页码),进行数据查询,然后查完数据后返回给前台的同时也要将页面返回给前台,好让前台结合CSS在分页样式中高亮显示出当前页。

步骤大体可以分为以下几步。

1.后台sql查询数据时(底层我用的是Mysql数据库)

前台只需要传递一个pageNum,然后后台定义个页面大小的常量吧,我是定义到Constant类里面,作为一个常量来使用的。

  /**
     * 分页页面参数
     */
    public static final Integer PAGESIZE = 10;

使用的时候用Constant.PAGESIZE来调用。

这时候我们需要了解mysql分页的sql的实现是这样的:

在mysql中,我们用limit来实现分页数据的查询,limit A,B 表示从A开始,往后取B个数。

对于我们来说,第一页就是0-9这10条记录(mysql记录的索引是从0开始的),所以我们第一页取的数据对应的sql是 limit 0,10;以此类推第二页是  limit 10,10,第三页是 limit  20,10  ......

开始的索引值需要我们进行一个简单的计算,Integer startIndex = (pageNum-1)*10,,不理解的将pageNum值代入想一想就知道了。

limit startIndex ,PAGESIZE始终都是放在查询的最后面,即前面什么各种where ,group by, order by全部写好后再接limit

2.后台pageVo类的构建

因为前台需要后台的数据比较多,所以我们将它们封装到一个pageVo对象里面。

下面是我pageVo类的定义

package com.bada.core.vo;

import java.io.Serializable;
import java.util.Map;

/**
 * @author Kevin
 * 用于分页的类
 */
public class PageVo implements Serializable {
	private int curPage;//当前页
	private int pageSize;//每页的大小
	private int totalRows;//总记录数
	private int totalPages;//总页数
    private String queryCondition; //查询条件(字符串),用户将查询条件穿到前台然后再传回来
    private Map<String,Object> queryConditions; //查询条件,针对多条件

    public Map<String, Object> getQueryConditions() {
        return queryConditions;
    }
    public void setQueryConditions(Map<String, Object> queryConditions) {
        this.queryConditions = queryConditions;
    }
    public int getCurPage() {
		return curPage;
	}
	public void setCurPage(int curPage) {
		this.curPage = curPage;
	}
	public int getPageSize() {
		return pageSize;
	}
	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}
	public int getTotalRows() {
		return totalRows;
	}
	public void setTotalRows(int totalRows) {
		this.totalRows = totalRows;
	}
	public int getTotalPages() {
		return totalPages;
	}
	public void setTotalPages(int totalPages) {
		this.totalPages = totalPages;
	}
    public String getQueryCondition() {
        return queryCondition;
    }
    public void setQueryCondition(String queryCondition) {
        this.queryCondition = queryCondition;
    }

    @Override
    public String toString() {
        return "PageVo{" +
                "curPage=" + curPage +
                ", pageSize=" + pageSize +
                ", totalRows=" + totalRows +
                ", totalPages=" + totalPages +
                ", queryCondition='" + queryCondition + '\'' +
                ", queryConditions=" + queryConditions +
                '}';
    }
}

其中加的queryCondition和queryConditions变量是关于带查询条件的页面分页时存入查询条件,传到前台,然后点击下一页时传到后台时不会因为缺失查询条件而加载出的数据位空了。

后台需要new一个PageVo的对象出来,然后set对应的参数值,curPage就是pageNum,pageSize是页面大小,这里要注意的事,在进行数据查询后,还需要对满足条件的所有记录做一个计数,去获取总数值。一般 select count(ID) from ** where **=**, 一般不要count(*),查询效率会低很多的,count(0)就可以了,当然count(主键)会更快,因为主键是加了索引的。

totalRows对应刚才查询出来的总数,totalPages也是需要我们去计数的。思考一下,一共需要的页面数,我们先弄几个例子来推敲一下,如果有40条记录,根据1页是10条记录,那么就是4页,如果有38条记录,也是4页,其实就是一个总数除以页面大小向上取整,我们写一个方法去实现。

public class FormatUtils {
    /**
     * 向上取整    例如: 30条数据,每页8条  一共4页
     * @param total
     * @param pageSize
     * @return
     */
    public static int getPageTotal(int total,int pageSize){
        if(pageSize == 0){//分母不能为0
            return 0;
        }
        return (int)Math.ceil((double)total/pageSize);
    }
}

java自带了Math.ceil用来取大于或等于某个数的最小整数。

如果有一个查询条件就set到queryCondition中去,如果有多个就封装到map再set到queryCondtions里面去、具体前台怎么取在后面诉述、

3.前台jstl构建页面元素。

开始是写在页面上一大串jstl代码来生成html代码,后来直接封装到自定义标签中要方便的多,先展示一下jstl是如何写的。

<div class="page mg-auto">
<ul class="pagination">
            <c:if test="${pageVo.totalPages > 0}">
                <li><a href="javascript:onSelectPage(${pageVo.curPage - 1})">«</a></li>
                <c:if test="${pageVo.totalPages <= 10}">
                    <c:forEach var="i" begin="1" end="${pageVo.totalPages}">
                        <c:choose>
                            <c:when test="${i == pageVo.curPage}">
                                <li class="active"><a href="javascript:onSelectPage(${i})">${i}</a></li>
                            </c:when>
                            <c:otherwise>
                                <li><a href="javascript:onSelectPage(${i})">${i}</a></li>
                            </c:otherwise>
                        </c:choose>
                    </c:forEach>
                </c:if>
                <c:if test="${pageVo.totalPages > 10}">
                    <c:if test="${pageVo.curPage < 10}">
                        <c:forEach var="i" begin="1" end="10">
                            <c:choose>
                                <c:when test="${i == pageVo.curPage}">
                                    <li class="current"><a href="javascript:onSelectPage(${i})">${i}</a></li>
                                </c:when>
                                <c:otherwise>
                                    <li><a href="javascript:onSelectPage(${i})">${i}</a></li>
                                </c:otherwise>
                            </c:choose>
                        </c:forEach>
                    </c:if>
                    <c:if test="${pageVo.curPage >= 10}">
                        <c:forEach var="j" begin="${pageVo.curPage-5}" end="${pageVo.curPage+4}">
                            <c:if test="${j <= pageVo.totalPages}">
                                <c:choose>
                                    <c:when test="${j == pageVo.curPage}">
                                        <li class="current"><a href="javascript:onSelectPage(${j})">${j}</a></li>
                                    </c:when>
                                    <c:otherwise>
                                        <li><a href="javascript:onSelectPage(${j})">${j}</a></li>
                                    </c:otherwise>
                                </c:choose>
                            </c:if>
                        </c:forEach>
                    </c:if>
                </c:if>
                <li><a href="javascript:onSelectPage(${pageVo.curPage + 1})">»</a></li>
            </c:if>
</ul>
</div>

后来才发现上面的代码其实可以用自定义标签实现,页面上一行代码就搞定,重用性高多了~  后面讲这个!!

具体的实现逻辑是模仿百度分页的走的,

需要分析的逻辑如下(步步递进):

1、一条记录都没有,不显示页码。   判断pageVo的totalPages是否大于0,如果大于0,才去生成分页样式

2、如果总页数小于10,则写一个循环,从1开始,循环到总页数,显示N页(N为totalPages),显示这N页的同时,根据pageVo里面的curPage判断哪一页需要高亮显示出来。

3、如果总页数大于10,小于10的部分显示效果如上,大于10的时候,高亮页面始终在中间区域,即以当前页curPage做为条件,它的左边显示5个,右边显示4个。(具体效果可以看看百度搜索完结果的最下方)

一次性最多展示10页,然后高亮显示在中间(页面大于10)。

每一个a标签都要加js函数,当点击的时候跳到下面的函数里面。

<c:if test="${!empty pageVo}"> <%--防止首次进入该页面时没有pageVo而出js错误--%>
    <script type="text/javascript">
        function onSelectPage(curPage){
            if(curPage>=1 && curPage<=${pageVo.totalPages}){
                if (curPage != ${pageVo.curPage}) { //当前页点击禁用跳转
                         window.location.href="${pageContext.request.contextPath}/customer/queryAllSalesShippers?pageNum="+curPage;
                }
            }
        }
    </script>
</c:if>

如果带查询条件的这么去写

window.location.href="${pageContext.request.contextPath}/customer/querySalesShipperCustomer?condition=${pageVo.queryCondition}&pageNum="+curPage;

当然window.location.href=""后面的连接写你查询数据的那个action路径。

关于对应的前端样式是前端去写的,只要有带高亮样式的分页的html代码就行,这里我也贴出css代码好了。

具体样子

/*------------------------------分页 tag defines-------------------------------*/
.page{width:80%;text-align:center;margin-top:80px;}
.pagination {
display: inline-block;
padding-left: 0;
margin: 20px 0;
border-radius: 2px;}
.pagination>li {
display: inline;
}
:before, :after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
:before, :after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.pagination>li:first-child>a, .pagination>li:first-child>span {
margin-left: 0;
border-top-left-radius: 2px;
border-bottom-left-radius: 2px;
}
.pagination>li>a, .pagination>li>span {
position: relative;
float: left;
padding: 6px 12px;
margin-left: -1px;
line-height: 1.42857143;
color: #428bca;
text-decoration: none;
background-color: #fff;
border: 1px solid #ddd;
}
a {
text-decoration: none;
}
a {
background: 0 0;
}
.pagination>.active>a, .pagination>.active>span, .pagination>.active>a:hover, .pagination>.active>span:hover, .pagination>.active>a:focus, .pagination>.active>span:focus {
color: #fff;
cursor: default;
background-color: #428bca;
border-color: #428bca;
}
.pagination>li>a:hover, .pagination>li>span:hover, .pagination>li>a:focus, .pagination>li>span:focus {
color: #2a6496;
background-color: #eee;
border-color: #ddd;
}
.pagination>.active>a, .pagination>.active>span, .pagination>.active>a:hover, .pagination>.active>span:hover, .pagination>.active>a:focus, .pagination>.active>span:focus {
color: #fff;
cursor: default;
background-color: #428bca;
border-color: #428bca;
}
.pagination>li>a, .pagination>li>span {
position: relative;
float: left;
padding: 6px 12px;
margin-left: -1px;
line-height: 1.42857143;
color: #428bca;
text-decoration: none;
background-color: #fff;
border: 1px solid #ddd;
}

我写的分页,简单步骤就是3步,后台pageVo构建,前台jstl生成分页模块,然后加个js函数去进行跳转查询

=========================================================我是分割线========================================================

下面说一下关于自定义标签的实现

具体的思路就是用java代码去将html代码打印出来,就跟servlet用输出流打印页面一样。

1.构建自定义标签类

package com.bada.biz.service;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;
import com.bada.core.vo.PageVo;

/**
 * Created by Kevin on 2014/11/2.
 * pageVo的自定义标签类
 */
public class PageVoTag extends TagSupport {

    private PageVo pageVo;

    @Override
    public int doStartTag() throws JspException {
        try {
            JspWriter out = this.pageContext.getOut();
            if(pageVo == null) {
                return SKIP_BODY;
            }
            if (pageVo.getTotalPages() > 0) {
                out.println("<li><a href=\"javascript:onSelectPage("+(pageVo.getCurPage()-1)+")\">«</a></li>");
                if (pageVo.getTotalPages() <= 10) {
                    for (int i = 1; i <= pageVo.getTotalPages(); i++) {
                        if (i == pageVo.getCurPage()) {
                            out.println("<li class=\"active\"><a href=\"javascript:onSelectPage("+i+")\">"+i+"</a></li>");
                        } else {
                            out.println("<li><a href=\"javascript:onSelectPage("+i+")\">"+i+"</a></li>");
                        }
                    }
                }

                if (pageVo.getTotalPages() > 10) {
                    if (pageVo.getCurPage() < 10) {
                        for (int i = 1; i <= 10; i++) {
                            if (i == pageVo.getCurPage()) {
                                out.println("<li class=\"current\"><a href=\"javascript:onSelectPage("+i+")\">"+i+"</a></li>");
                            } else {
                                out.println("<li><a href=\"javascript:onSelectPage("+i+")\">"+i+"</a></li>");
                            }
                        }
                    }
                    if (pageVo.getCurPage() >= 10) {
                        for (int j = pageVo.getCurPage()-5;j <= pageVo.getCurPage()+4; j++) {
                            if (j <= pageVo.getTotalPages()) {
                                if (j == pageVo.getCurPage()){
                                    out.println("<li class=\"current\"><a href=\"javascript:onSelectPage("+j+")\">"+j+"</a></li>");
                                } else {
                                    out.println("<li><a href=\"javascript:onSelectPage("+j+")\">"+j+"</a></li>");
                                }
                            }
                        }
                    }
                }
                out.println("<li><a href=\"javascript:onSelectPage("+(pageVo.getCurPage()+1)+")\">»</a></li>");
            }

        } catch(Exception e) {
            throw new JspException(e.getMessage());
        }
        return SKIP_BODY;
    }

    @Override
    public int doEndTag() throws JspException {
        return EVAL_PAGE;
    }

    @Override
    public void release() {
        super.release();
        this.pageVo = null;
    }

    public PageVo getPageVo() {
        return pageVo;
    }

    public void setPageVo(PageVo pageVo) {
        this.pageVo = pageVo;
    }
}

可以看到,代码明显比jstl少很多,看来还是ava代码好使哇。这个类可能需要下载对应的jar包,这个自己百度一下。

2.自定义标签文件    命名为  pageVo.tld

<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
        version="2.0">

    <tlib-version>1.0</tlib-version>
    <short-name>cc</short-name>
    <uri>/pageTaglib</uri>

    <tag>
        <name>showPaging</name>
        <tag-class>com.bada.biz.service.PageVoTag</tag-class>
        <body-content>empty</body-content>
        <attribute>
            <name>pageVo</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
    </tag>

</taglib>

里面对应的tag-class就是上面写的那个类,pageVo为传入的参数,到时候前台用${pageVo}赋值这个参数。

3.web.xml里面的配置

    <!--配置自定义标签-->
    <jsp-config>
        <taglib>
            <taglib-uri>/pageTaglib</taglib-uri>
            <taglib-location>/WEB-INF/tld/pageVo.tld</taglib-location>
        </taglib>
    </jsp-config>

加在web-app标签里面一级就行了

4.jsp页面使用

引用标签:uri是上面定义的uri,prefix为前缀名,任意取的

<%@ taglib uri="/pageTaglib" prefix="pv"%>

使用标签

<div class="page mg-auto">
            <ul class="pagination">
                <pv:showPaging pageVo="${pageVo}" />
            </ul>
        </div>

一行代码搞定。。再也不用不停copy 那一大串jstl代码了。

至此 分页模块搞定了,相关文件下载http://download.csdn.net/detail/tro_picana/8151805

时间: 2024-10-19 11:44:50

详谈javaWeb分页的实现(模拟百度分页)的相关文章

模拟百度分页算法实现

定义变量 pageSize 每一页显示的记录条件 pageNow 当前页,初始默认值为1 pageCount 总页数,有pageSize和数据库总记录数决定 公式:double res = select count(id) from 记录表 // 使用Math函数将结果向上取整 pageCount = (int) Math.ceil(res / pageSize); pageNow是传入参数,pageCount是传出参数,pageSize内部使用页码分页显示 pageNum 每一页显示的页码数,

住javaWeb分页实现(模拟百度首页)

本文来源于 http://blog.csdn.net/tjpu_lin/article/details/41050475 近期在开发一个项目,项目中有非常多数据展示的模块.所以要用到分页,网上搜了非常多分页的样例,可是非常多实现的方法和自身的代码实例耦合度太高.导致直接拿来用根本不行. 于是自己仅仅能亲自上阵了,关于分页实现大体逻辑是前台须要和后台相互传递页面參数(比如当前页面,页面大小.总共页数等),后台主要接受前台穿过来的pageNum(当前页码),进行数据查询,然后查完数据后返回给前台的同

AJAX实现分页--模拟百度搜索分页

第一部分:效果与分析 1.百度分页组件: 2.自己实现的分页: 3.分析: 百度搜索分页,如果总页数大于10,用户最多只能看到10页内容,不足10页显示全部,当点击下一页时,数字页标向前移动一个单位,当点击上一页时向后移动一个单位. 第二部分:后台实现: 1.实现思路: 后台的处理思想是这样的,通过AJAX向后台发送请求,携带一个分页对象PageBean传过去,查询完毕后返回一个新的PageBean对象. 前台传入的PageBean对象参数: 属性 名称 是否必须 默认值 pageSize 每页

JAVA仿百度分页

最近在做一个仿百度网盘的网页小应用,找到了一个优雅简洁的分页插件,和百度搜索的分页很相似,对他进行了二次封装,拿出来跟大家分享下 插件源码 /** * This jQuery plugin displays pagination links inside the selected elements. * * This plugin needs at least jQuery 1.4.2 * * @author Gabriel Birke (birke *at* d-scribe *dot* de

实现百度分页效果的工具类

一个工具类,可实现百度分页效果,前5后4 import java.io.IOException; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.TagSupport; import org.apa

百度分页在某种情况下突然变了

百度分页在某种情况下突然变了 挺奇怪的,我是先搜索某个关键字,然后点视频,然后再点回来网页,就出现了这个新分页页面,奇怪吧,嘿嘿 你们有没有碰到过?

php实现仿百度分页

本文主要和大家分享php实现仿百度分页的实例,先来看一下效果图. 基本策略 1, 首先要查询总记录数 2, 设置每页显示的数量并计算总页数 3, 增加一个get传值num代表当前访问的是哪一页,如果没有num的get传值,应该设置默认的当前页为第一页! 4, 就拿一个字符串来保存页码链接,这个字符串也叫作页码字符串! 5, 在查询的时候,就应该使用limit子句进行限制(limit子句分页原理) 完成仿百度分页功能 分页需求 1, 当前页是前3页的时候,显示的初始页$startNum是1,显示的

【知了堂学习笔记】JSP页面数据分页实现(一)——分页概念以及主流数据库的分页查询

一.分页简介 1.分页,就是一种将数据库里的数据一部分展示给用户的技术.为什么要这样做呢?因为一般来说用户在查询时数据是非常多的,当一个页面不能显示所有数据时,我们就要对查询的数据进行分页,就像我们的书本分成一页一页一样.最简单的例子就是百度,当你百度时,成千上万的数据,并不是呈现在一个页面的. 2.分页的实现方式 1)假分页(不推荐):什么是假分页呢?假分页就是一次性将数据库里的数据全部取出来,存储在页面中,然后再将数据分别展示出来.这种假分页在数据少的还可以玩玩,当数据多起来的时候,这种方式

Mybatis最入门---分页查询(拦截器分页原理及实现)

[一步是咫尺,一步即天涯] 前文,我们演示了物理分页的Sql实现方式,这种方式使得我们每次在编写查询服务时,不断的重复造轮子.这样的代码实现方式就显得十分的笨拙了.本文是Mybatis分页查询的最后一片内容,我们将介绍基于拦截器的,精巧的实现方式.在阅读这篇文章之前,强烈建议各位看官能够先阅读上文.这样就能对下文我们提及的各种对象及他们之间的关系有一个清晰的关系.好了,废话不多讲,开始我们的正文部分吧. 准备工作: a.操作系统 :win7 x64 b.基本软件:MySQL,Mybatis,SQ