MyBatis攔截器實(shí)現(xiàn)分頁(yè)功能的實(shí)現(xiàn)方法
MyBatis攔截器實(shí)現(xiàn)分頁(yè)功能的實(shí)現(xiàn)方法
前言:
首先說(shuō)下實(shí)現(xiàn)原理。使用攔截器攔截原始的sql,然后加上分頁(yè)查詢(xún)的關(guān)鍵字和屬性,拼裝成新的sql語(yǔ)句再交給mybatis去執(zhí)行。
除了業(yè)務(wù)代碼之外,需要寫(xiě)的東西不多,提幾個(gè)關(guān)鍵的:
1、分頁(yè)對(duì)象Page類(lèi)。給該對(duì)象設(shè)置一個(gè)當(dāng)前頁(yè)數(shù)(前端給)、總記錄數(shù)(攔截器內(nèi)賦值)2個(gè)參數(shù),他就能幫你計(jì)算出分頁(yè)sql語(yǔ)句用的2個(gè)參數(shù)。
/** * 分頁(yè)對(duì)應(yīng)的實(shí)體類(lèi) */ public class Page { /** * 總條數(shù) */ private int totalNumber; /** * 當(dāng)前第幾頁(yè) */ private int currentPage; /** * 總頁(yè)數(shù) */ private int totalPage; /** * 每頁(yè)顯示條數(shù) */ private int pageNumber = 5; /** * 數(shù)據(jù)庫(kù)中l(wèi)imit的參數(shù),從第幾條開(kāi)始取 */ private int dbIndex; /** * 數(shù)據(jù)庫(kù)中l(wèi)imit的參數(shù),一共取多少條 */ private int dbNumber; /** * 根據(jù)當(dāng)前對(duì)象中屬性值計(jì)算并設(shè)置相關(guān)屬性值 */ public void count() { // 計(jì)算總頁(yè)數(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è)置當(dāng)前頁(yè)數(shù) // 總頁(yè)數(shù)小于當(dāng)前頁(yè)數(shù),應(yīng)將當(dāng)前頁(yè)數(shù)設(shè)置為總頁(yè)數(shù) if(this.totalPage < this.currentPage) { this.currentPage = this.totalPage; } // 當(dāng)前頁(yè)數(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)鍵的攔截器實(shí)現(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; /** * 分頁(yè)攔截器 * * @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"); //通過(guò)MetaObject元數(shù)據(jù)取得方法名id:com.XXX.queryMessageListByPage String id = mappedStatement.getId(); //匹配在mybatis中定義的與分頁(yè)有關(guān)的查詢(xún)id if (id.matches(".+ByPage$")) { //BoundSql中有原始的sql語(yǔ)句和對(duì)應(yīng)的查詢(xún)參數(shù) BoundSql boundSql = statementHandler.getBoundSql(); Map<String, Object> params = (Map<String, 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)? 因?yàn)閿?shù)據(jù)表的列是從1開(kāi)始計(jì)數(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 * 被攔截的對(duì)象 */ public Object plugin(Object target) { // 如果將攔截器類(lèi)比喻為代購(gòu)票的公司,那this就是代購(gòu)業(yè)務(wù)員(進(jìn)入方法前是無(wú)代理購(gòu)票能力業(yè)務(wù)員,進(jìn)入后成為有代理能力的業(yè)務(wù)員) // 通過(guò)注解獲取攔截目標(biāo)的信息,如果不符合攔截要求就返回原目標(biāo),如果符合則使用動(dòng)態(tài)代理生成代理對(duì)象 return Plugin.wrap(target, this); } public void setProperties(Properties properties) { // TODO Auto-generated method stub } }
3、mybatis-config.xml里面注冊(cè)自己寫(xiě)的攔截器
<!-- 自定義的分頁(yè)攔截器 --> <plugins> <plugin interceptor="你寫(xiě)的攔截器全類(lèi)名"> </plugin> </plugins>
Dao層相關(guān)的mapper.xml里面的sql語(yǔ)句不用做改動(dòng)。
4、前端需要給后端一個(gè)顯示哪一頁(yè)的參數(shù),通過(guò)service層組裝查詢(xún)參數(shù)之后交給MyBatis去查分頁(yè)數(shù)據(jù),我定義的分頁(yè)DAO接口返回的數(shù)據(jù)是一個(gè)list,包含了分頁(yè)查詢(xún)結(jié)果。前端可以用jquery_pagination插件去實(shí)現(xiàn)分頁(yè)的展示,具體去官方github看怎么設(shè)置吧。
<!--pagination需要的腳本--> <% // 獲取請(qǐng)求的上下文 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"> // 點(diǎn)擊分頁(yè)按鈕以后觸發(fā)的動(dòng)作 function handlePaginationClick(new_page_index, pagination_container) { <!--從stuForm表單提交當(dāng)前頁(yè)的參數(shù).可以使用restful方式,讓springmvc使用@PathVariable關(guān)鍵字定義的形參去接。這2個(gè)參數(shù)是分頁(yè)控件自己提供的,不需要我們?nèi)プ约赫?,但是?jì)數(shù)從0開(kāi)始,而我們后臺(tái)分頁(yè)計(jì)數(shù)從1開(kāi)始,因此要手動(dòng)加1。 --> $("#stuForm").attr("action", "你定義的分頁(yè)查詢(xún)url/"+(new_page_index+1)); $("#stuForm").submit(); return false; } $(function(){ $("#News-Pagination").pagination(${result.totalRecord}, { items_per_page:${result.pageSize}, // 每頁(yè)顯示多少條記錄 current_page:${result.currentPage} - 1, // 當(dāng)前顯示第幾頁(yè)數(shù)據(jù) num_display_entries:8, // 分頁(yè)顯示的條目數(shù) next_text:"下一頁(yè)", prev_text:"上一頁(yè)", num_edge_entries:2, // 連接分頁(yè)主體,顯示的條目數(shù) callback:handlePaginationClick(當(dāng)前頁(yè),分頁(yè)div的id), //執(zhí)行的回調(diào)函數(shù) load_first_page:false //防止頁(yè)面一直刷新( 這條非常重要!) }); }); </script> <!-- 這部分用c:forEach標(biāo)簽打印查詢(xún)結(jié)果的表格--> <!--分頁(yè)控件名稱(chēng)--> <div id="News-Pagination"></div>
寫(xiě)這篇總結(jié)的目的是希望形成一個(gè)分頁(yè)功能的整體解決方案(前端+后端都涵蓋到)。4月17、18日開(kāi)始我會(huì)寫(xiě)一個(gè)小系統(tǒng)將前段時(shí)間所學(xué)都用上,完了之后會(huì)回來(lái)更新這篇文章里面不正確的地方。
如有疑問(wèn)請(qǐng)留言或者到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
MySQL中replace into與replace區(qū)別詳解
本文主要介紹了MySQL中replace into與replace區(qū)別詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08MySQL limit使用方法以及超大分頁(yè)問(wèn)題解決
這篇文章主要給大家介紹了關(guān)于MySQL limit使用方法以及超大分頁(yè)問(wèn)題解決的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用MySQL具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10MySQL中count()和count(1)有何區(qū)別以及哪個(gè)性能最好詳解
count是一個(gè)函數(shù),用來(lái)統(tǒng)計(jì)數(shù)據(jù),但是count函數(shù)傳入的參數(shù)有很多種,比如count(1)、count(*)、count(字段)等,下面這篇文章主要給大家介紹了關(guān)于MySQL中count()和count(1)有何區(qū)別以及哪個(gè)性能最好的相關(guān)資料,需要的朋友可以參考下2022-08-08MySQL 存儲(chǔ)過(guò)程中執(zhí)行動(dòng)態(tài)SQL語(yǔ)句的方法
這篇文章主要介紹了MySQL 存儲(chǔ)過(guò)程中執(zhí)行動(dòng)態(tài)SQL語(yǔ)句的方法,需要的朋友可以參考下2014-08-08MySQL開(kāi)啟慢查詢(xún)方法及實(shí)例
這篇文章主要介紹了MySQL開(kāi)啟慢查詢(xún)方法及實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04MySQL數(shù)據(jù)庫(kù)定時(shí)備份的實(shí)現(xiàn)方法
這篇文章主要介紹了MySQL數(shù)據(jù)庫(kù)的定時(shí)備份的相關(guān)知識(shí),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-04-04MySql用DATE_FORMAT截取DateTime字段的日期值
MySql截取DateTime字段的日期值可以使用DATE_FORMAT來(lái)格式化,使用方法如下2014-08-08mysql-connector-java與Mysql、Java的對(duì)應(yīng)版本問(wèn)題
這篇文章主要介紹了mysql-connector-java與Mysql、Java的對(duì)應(yīng)版本問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11