MyBatis攔截器實現(xiàn)分頁功能的實現(xiàn)方法
前言:
首先說下實現(xiàn)原理。使用攔截器攔截原始的sql,然后加上分頁查詢的關(guān)鍵字和屬性,拼裝成新的sql語句再交給mybatis去執(zhí)行。
除了業(yè)務(wù)代碼之外,需要寫的東西不多,提幾個關(guān)鍵的:
1、分頁對象Page類。給該對象設(shè)置一個當前頁數(shù)(前端給)、總記錄數(shù)(攔截器內(nèi)賦值)2個參數(shù),他就能幫你計算出分頁sql語句用的2個參數(shù)。
/**
* 分頁對應(yīng)的實體類
*/
public class Page {
/**
* 總條數(shù)
*/
private int totalNumber;
/**
* 當前第幾頁
*/
private int currentPage;
/**
* 總頁數(shù)
*/
private int totalPage;
/**
* 每頁顯示條數(shù)
*/
private int pageNumber = 5;
/**
* 數(shù)據(jù)庫中l(wèi)imit的參數(shù),從第幾條開始取
*/
private int dbIndex;
/**
* 數(shù)據(jù)庫中l(wèi)imit的參數(shù),一共取多少條
*/
private int dbNumber;
/**
* 根據(jù)當前對象中屬性值計算并設(shè)置相關(guān)屬性值
*/
public void count() {
// 計算總頁數(shù)
int totalPageTemp = this.totalNumber / this.pageNumber;
int plus = (this.totalNumber % this.pageNumber) == 0 ? 0 : 1;
totalPageTemp = totalPageTemp + plus;
if(totalPageTemp = 0) {
totalPageTemp = 1;
}
this.totalPage = totalPageTemp;
// 設(shè)置當前頁數(shù)
// 總頁數(shù)小于當前頁數(shù),應(yīng)將當前頁數(shù)設(shè)置為總頁數(shù)
if(this.totalPage this.currentPage) {
this.currentPage = this.totalPage;
}
// 當前頁數(shù)小于1設(shè)置為1
if(this.currentPage 1) {
this.currentPage = 1;
}
// 設(shè)置limit的參數(shù)
this.dbIndex = (this.currentPage - 1) * this.pageNumber;
this.dbNumber = this.pageNumber;
}
public int getTotalNumber() {
return totalNumber;
}
public void setTotalNumber(int totalNumber) {
this.totalNumber = totalNumber;
this.count();
}
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public int getPageNumber() {
return pageNumber;
}
public void setPageNumber(int pageNumber) {
this.pageNumber = pageNumber;
this.count();
}
public int getDbIndex() {
return dbIndex;
}
public void setDbIndex(int dbIndex) {
this.dbIndex = dbIndex;
}
public int getDbNumber() {
return dbNumber;
}
public void setDbNumber(int dbNumber) {
this.dbNumber = dbNumber;
}
}
2、關(guān)鍵的攔截器實現(xiàn)
package com.imooc.interceptor;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Map;
import java.util.Properties;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import com.imooc.entity.Page;
/**
* 分頁攔截器
*
* @author Skye
*
*/
@Intercepts({
@Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class }) })
public class PageInterceptor implements Interceptor {
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY,
SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
//通過MetaObject元數(shù)據(jù)取得方法名id:com.XXX.queryMessageListByPage
String id = mappedStatement.getId();
//匹配在mybatis中定義的與分頁有關(guān)的查詢id
if (id.matches(".+ByPage$")) {
//BoundSql中有原始的sql語句和對應(yīng)的查詢參數(shù)
BoundSql boundSql = statementHandler.getBoundSql();
MapString, Object> params = (MapString, Object>) boundSql.getParameterObject();
Page page = (Page) params.get("page");
String sql = boundSql.getSql();
String countSql = "select count(*)from (" + sql + ")a";
Connection connection = (Connection) invocation.getArgs()[0];
PreparedStatement countStatement = connection.prepareStatement(countSql);
ParameterHandler parameterHandler = (ParameterHandler) metaObject.getValue("delegate.parameterHandler");
parameterHandler.setParameters(countStatement);
ResultSet rs = countStatement.executeQuery();
if (rs.next()) {
//為什么是getInt(1)? 因為數(shù)據(jù)表的列是從1開始計數(shù)
page.setTotalNumber(rs.getInt(1));
System.out.println("攔截器得知page的記錄總數(shù)為:" + page.getTotalNumber());
}
String pageSql = sql + " limit " + page.getDbIndex() + "," + page.getDbNumber();
metaObject.setValue("delegate.boundSql.sql", pageSql);
}
return invocation.proceed();
}
/**
* @param target
* 被攔截的對象
*/
public Object plugin(Object target) {
// 如果將攔截器類比喻為代購票的公司,那this就是代購業(yè)務(wù)員(進入方法前是無代理購票能力業(yè)務(wù)員,進入后成為有代理能力的業(yè)務(wù)員)
// 通過注解獲取攔截目標的信息,如果不符合攔截要求就返回原目標,如果符合則使用動態(tài)代理生成代理對象
return Plugin.wrap(target, this);
}
public void setProperties(Properties properties) {
// TODO Auto-generated method stub
}
}
3、mybatis-config.xml里面注冊自己寫的攔截器
!-- 自定義的分頁攔截器 -->
plugins>
plugin interceptor="你寫的攔截器全類名">
/plugin>
/plugins>
Dao層相關(guān)的mapper.xml里面的sql語句不用做改動。
4、前端需要給后端一個顯示哪一頁的參數(shù),通過service層組裝查詢參數(shù)之后交給MyBatis去查分頁數(shù)據(jù),我定義的分頁DAO接口返回的數(shù)據(jù)是一個list,包含了分頁查詢結(jié)果。前端可以用jquery_pagination插件去實現(xiàn)分頁的展示,具體去官方github看怎么設(shè)置吧。
!--pagination需要的腳本-->
%
// 獲取請求的上下文
String context = request.getContextPath();
%>
link href="../css/pagination.css" rel="external nofollow" rel="stylesheet" type="text/css"/>
script type="text/javascript" src="../js/jquery-1.11.3.js">/script>
script type="text/javascript" src="../js/jquery.pagination.js">/script>
script type="text/javascript">
// 點擊分頁按鈕以后觸發(fā)的動作
function handlePaginationClick(new_page_index, pagination_container) {
!--從stuForm表單提交當前頁的參數(shù).可以使用restful方式,讓springmvc使用@PathVariable關(guān)鍵字定義的形參去接。這2個參數(shù)是分頁控件自己提供的,不需要我們?nèi)プ约赫遥怯嫈?shù)從0開始,而我們后臺分頁計數(shù)從1開始,因此要手動加1。 -->
$("#stuForm").attr("action", "你定義的分頁查詢url/"+(new_page_index+1));
$("#stuForm").submit();
return false;
}
$(function(){
$("#News-Pagination").pagination(${result.totalRecord}, {
items_per_page:${result.pageSize}, // 每頁顯示多少條記錄
current_page:${result.currentPage} - 1, // 當前顯示第幾頁數(shù)據(jù)
num_display_entries:8, // 分頁顯示的條目數(shù)
next_text:"下一頁",
prev_text:"上一頁",
num_edge_entries:2, // 連接分頁主體,顯示的條目數(shù)
callback:handlePaginationClick(當前頁,分頁div的id), //執(zhí)行的回調(diào)函數(shù)
load_first_page:false //防止頁面一直刷新( 這條非常重要!)
});
});
/script>
!-- 這部分用c:forEach標簽打印查詢結(jié)果的表格-->
!--分頁控件名稱-->
div id="News-Pagination">/div>
寫這篇總結(jié)的目的是希望形成一個分頁功能的整體解決方案(前端+后端都涵蓋到)。4月17、18日開始我會寫一個小系統(tǒng)將前段時間所學都用上,完了之后會回來更新這篇文章里面不正確的地方。
如有疑問請留言或者到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
您可能感興趣的文章:- mybatisplus 的SQL攔截器實現(xiàn)關(guān)聯(lián)查詢功能
- Mybatis自定義攔截器和插件開發(fā)詳解
- mybatis 自定義實現(xiàn)攔截器插件Interceptor示例
- mybatis 通過攔截器打印完整的sql語句以及執(zhí)行結(jié)果操作
- Mybatis Plugin攔截器開發(fā)過程詳解
- 簡單了解mybatis攔截器實現(xiàn)原理及實例
- mybatis攔截器實現(xiàn)通用權(quán)限字段添加的方法
- Mybatis中攔截器的簡單實現(xiàn)方法
- mybatis攔截器與分頁插件實例教程
- Mybatis Interceptor 攔截器的實現(xiàn)
- MyBatis攔截器的原理與使用