java分页的实现,插件PageHelper的使用及原理


java分页的实现,插件PageHelper的使用及原理

如果你只希望知道PageHelper的用法,直接去github查看官网文档 Mybatis-PageHelper.

 

1.关于分页。

在web项目中,分页是一个常见的功能。在我刚学完javaweb的时候在没有用任何框架的情况下做过分页,代码非常的冗余、难看,后台每个POJO类的增删改查里都需要写:(pageSize为每页大小,pageNum为查询的页数)

 

getList(int pageSize,int pageNum); 

 


getTotal();

 

而前端也要写多个jsp,一个分页就对应了一个jsp。导致不管是前后台,代码都大量重复,实在是太不优雅了。

 

2.PageHelper的优缺点。

PageHelper做的是什么呢?它封装了分页的后台部分,说得更简单点,就是你不需要每个POJO类的增删改查里都包括那两个方法了,它帮你做了。你只需要有一个selectAll的方法,它会根据你使用的数据库来将你selectAll的sql改装成一个分页查询的sql,并顺带生成一个查询总数的sql。

java 页面分析工具 java分页插件pagehelper_java 页面分析工具

如图,对应不同的数据库有不同的方言,如常见的Mysql,分页关键字是limit,它就是这样组装你的sql。

 

@Override

 


    public String getPageSql(String sql, Page page, CacheKey pageKey) {

 


        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);

 


        sqlBuilder.append(sql);

 


        if (page.getStartRow() == 0) {

 


            sqlBuilder.append(" LIMIT ");

 


            sqlBuilder.append(page.getPageSize());

 


        } else {

 


            sqlBuilder.append(" LIMIT ");

 


            sqlBuilder.append(page.getStartRow());

 


            sqlBuilder.append(",");

 


            sqlBuilder.append(page.getPageSize());

 


            pageKey.update(page.getStartRow());

 


        }

 


        pageKey.update(page.getPageSize());

 


        return sqlBuilder.toString();

 


    }

 

 

 

PageHelper不仅帮你分页查询了数据,在返回时直接返回Page对象,里更是封装了许多分页信息。但是在前后台json数据交互时,由于Page对象继承自ArrayList,json不会保留其分页信息,所以在使用时往往是这样使用的:

 

@Override

 


	public PageInfo<TopicPost> selectAllPublicTopicPost(int pageNum) {

 


		int pageSize = 10;

 


		PageInfo<TopicPost> topicPostList = new PageInfo<TopicPost>();//主题帖表


 


		try {

 


			PageHelper.startPage(pageNum, pageSize);

 


			topicPostList =  ((Page<TopicPost>)topicPostDao.daoSelectAllPublicTopicPost()).toPageInfo();

 


		} catch (Exception e) {

 


			log.error("查询状态正常的主题帖失败!"+e.toString());

 


			e.printStackTrace();

 


		}

 


		return topicPostList;

 


	}

即将查询出来的Page转为PageInfo(没有继承ArrayList),将你的PageInfo<Object>返回给前台就可以了。

 

 

至此,我们可以看到PageHelper的优缺点。

优点:封装分页sql,使我们不需要每个地方都去写分页的查询语句;同时,使我们select的sql语句向下兼容,换了数据库也不需要更改sql代码;

缺点:自带的Page对象转json时会丢失分页数据;而转为PageInfo对象时分页信息过多(这一点作者已在github上说明,建议自己实现PageInfo)

 

3.前端的实现。

在拿到后台传来的数据后,前端要做的要不少。考虑一个这样的分页: 

<<  <  1  2  3  4  5  >  >>   难点在中间的五个数字,通常情况下PageNum(当前你浏览的页数)在中间,每当翻页时五个数字都会发生变化,但如果总页数较小或者PageNum较小时则不一定发生变动,同时还需要注意总页数小于5的问题。

<< 为到第一页

<   为上一页

 firstNum 通常为PageNum - 2

 secondNum 通常为PageNum - 1

 thirdNum 通常为PageNum

 fourthNum 通常为PageNum + 1

 fifthNum 通常为PageNum + 2

>   为下一页

>>为最后一页

直接看代码:

 

//查看所有状态正常的主题帖

 


function selectAllPublicTopicPost(pageNum){

 


	var url = "/guestbook/rs/topicpost/selectallpublictopicpost"; 

 


	var json = JSON.stringify(pageNum);

 


	$.ajax({

 


	    url:url,

 


	    type:'POST',

 


	    async:true,

 


	    data: json,

 


	    contentType:"application/json",

 


	    dataType:'json',

 


	    success:function(data,textStatus,jqXHR){

 


	    	var firstNum = pageNum - 2;

 


	    	var secondNum = pageNum -1;

 


	    	var thirdNum = pageNum;

 


	    	var fourthNum = pageNum + 1;

 


	    	var fifthNum = pageNum + 2;

 


	    	var prePage = pageNum - 1;

 


	    	var nextPage = pageNum + 1;

 


	    	

 


	    	if(pageNum < 4 || data.pages < 6){

 


	    		firstNum = 1;

 


		    	secondNum = 2;

 


		    	thirdNum = 3;

 


		    	fourthNum = 4;

 


		    	fifthNum = 5;

 


	    	}

 


	    	else if(pageNum > data.pages-2){

 


	    		firstNum = data.pages-4;

 


		    	secondNum = data.pages-3;

 


		    	thirdNum = data.pages-2;

 


		    	fourthNum = data.pages-1;

 


		    	fifthNum = data.pages;

 


	    	}

 


	    	if(data.isFirstPage){

 


	    		prePage = 1;

 


	    	}

 


	    	if(data.isLastPage ){

 


	    		nextPage = data.pages;

 


	    	}

 


	    	var index_page = "<li><a onclick='selectAllPublicTopicPost(1)' aria-label='Previous'><span aria-hidden='true'><<</span></a></li>"

 


		    			  	+"<li><a onclick='selectAllPublicTopicPost("+prePage+")' aria-label='Previous'><span aria-hidden='true'><</span></a></li>"

 


		    			  	+"<li><a onclick='selectAllPublicTopicPost("+firstNum+")'>"+firstNum+"</a></li>";

 


		    			  	if(secondNum <= data.pages){

 


		    			  		index_page = index_page + "<li><a onclick='selectAllPublicTopicPost("+secondNum+")'>"+secondNum+"</a></li>";

 


		    			  	}

 


		    			  	if(thirdNum <= data.pages){

 


		    			  		index_page = index_page + "<li><a onclick='selectAllPublicTopicPost("+thirdNum+")'>"+thirdNum+"</a></li>";

 


		    			  	}

 


		    			  	if(fourthNum <= data.pages){

 


		    			  		index_page = index_page + "<li><a onclick='selectAllPublicTopicPost("+fourthNum+")'>"+fourthNum+"</a></li>";

 


		    			  	}

 


		    			  	if(fifthNum <= data.pages){

 


		    			  		index_page = index_page + "<li><a onclick='selectAllPublicTopicPost("+fifthNum+")'>"+fifthNum+"</a></li>";

 


		    			  	}

 


		    			  	index_page = index_page +"<li><a onclick='selectAllPublicTopicPost("+nextPage+")' aria-label='Next'><span aria-hidden='true'>></span></a></li>"

 


		    			  	+"<li><a onclick='selectAllPublicTopicPost("+data.pages+")' aria-label='Next'><span aria-hidden='true'>>></span></a></li>";

 


	    	$("#index_page").html(index_page);

 


	    	//以下内容不重要

 


	    	var tp = "";

 


	        jQuery.each( data.list,function(i,item){

 


	        	tp = tp + "<div class='col-lg-4'><a href='/guestbook/contents.html?topicPostId="


 


	             	+item.id

 



	                +"' target='_blank'>"

 


	                +item.title

 


	                +"</a></div><div class='col-lg-2'>"

 


	                +item.keyword

 


	                +"</div><div class='col-lg-2'>"

 


	                +vagueTime(new Date(item.time).toLocaleString())

 


	                +"</div><div class='col-lg-2'><a href='/guestbook/cust_info.html?uid=" 


 


	                +item.userId

 



	                +"' target='_blank'>"

 


	                +item.userName

 


	                +"</a></div><div class='col-lg-1'>"

 


	                +item.replyNumber

 


	                +"<br/><br/></div>";

 


            });

 


	        $("#topic_list").html(tp);       

 


	    }

 


	})

 


}

这样就是一个完整的分页的前后台实现,但前端依然是每一个分页都要去写这么一大段代码,还有改善空间。

 

 

4.综合解决方案。

后台:采用PageHelper查询出来的Page转为PageInfo,如果需求的查询功能比较简单或者对性能要求高,自己照着PageInfo实现一个MyPageInfo,其中只要自己需要的属性、方法即可。

前端:写一个page.js提供一个getPageArr的方法,对传来的做PageNum做处理,返回一个数组,即firstNum至fifthNum,当然,要注意数据库不到5页的返回哦。这样的话前端也避免了冗余代码。