java分頁的實現,外掛PageHelper的使用及原理
java分頁的實現,外掛PageHelper的使用及原理
https://blog.csdn.net/qq_25498677/article/details/69675664
如果你只希望知道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。
如圖,對應不同的資料庫有不同的方言,如常見的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頁的返回哦。這樣的話前端也避免了冗餘程式碼。