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頁的返回哦。這樣的話前端也避免了冗余代碼。