How does the MyBatis interceptor implement the paging function?
How to Implement the paging function of the MyBatis interceptor
Preface:
First, let's talk about the implementation principle. Use the Interceptor to intercept the original SQL statement, add the keywords and attributes of the paging query, assemble the new SQL statement, and submit it to mybatis for execution.
In addition to the Business Code, there are not many things to write. There are several key points:
1. Page Object Class. Set two parameters for this object: the current page number (given by the front end) and the total number of records (assigned by the interceptor). This allows you to calculate the two parameters used for paging SQL statements.
/*** Object class corresponding to the Page */public class Page {/*** Total number of items */private int totalNumber; /***** current page */private int currentPage;/***** total page number */private int totalPage; /*** number of lines per page */private int pageNumber = 5;/*** the limit parameter in the database, starting from the number of lines */private int dbIndex; /*** Number of limit parameters in the database */private int dbNumber; /*** calculate and set the relevant attribute value based on the attribute value of the current object */public void count () {// calculate the total number of pages 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; // set the current page number to be smaller than the current page number. Set the current page number to the total page number if (this. totalPage <this. currentPage) {this. currentPage = this. totalPage;} // set the current page number to 1 if (this. currentPage <1) {this. currentPage = 1;} // set the limit parameter 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. Key interceptor implementation
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.exe cutor. parameter. parameterHandler; import org.apache.ibatis.exe cutor. statement. statementHandler; import org. apache. ibatis. mapping. boundSql; import org. apache. ibatis. mapping. mappedStatement; import org. apache. ibat Is. 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;/*** Page blocker ** @ autho R 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, example E Jsonaobject. DEFAULT_OBJECT_FACTORY, SystemMetaObject. DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory (); MappedStatement mappedStatement = (MappedStatement) metaObject. getValue ("delegate. mappedStatement "); // method id obtained through MetaObject metadata: com. XXX. queryMessageListByPage String id = mappedStatement. getId (); // match the paging-related query id defined in mybatis if (id. matches (". + ByPage $ ") {// BoundSql contains the original SQL statement and the corresponding query parameter Bo. UndSql 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); Param EterHandler parameterHandler = (ParameterHandler) metaObject. getValue ("delegate. parameterHandler "); parameterHandler. setParameters (countStatement); ResultSet rs = countStatement.exe cuteQuery (); if (rs. next () {// Why is getInt (1 )? Because the columns in the data table count the page from 1. setTotalNumber (rs. getInt (1); System. out. println ("the interceptor knows the total number of pages:" + page. getTotalNumber ();} String pageSql = SQL + "limit" + page. getDbIndex () + "," + page. getDbNumber (); metaObject. setValue ("delegate. boundSql. SQL ", pageSql);} return invocation. proceed ();}/*** @ param target * blocked Object */public Object plugin (Object target) {// If the interceptor is compared to the ticket purchasing company, this is the purchase Clerk (the clerk without the ability to purchase tickets by proxy before entering the method) // obtain the information of the interception target through annotations, if the request does not meet the interception requirements, the original target is returned. If the request does, a dynamic proxy is used to generate the proxy object return Plugin. wrap (target, this);} public void setProperties (Properties properties) {// TODO Auto-generated method stub }}
3. register your own interceptor in the mybatis-config.xml
<! -- Custom page blocker --> <plugins> <plugin interceptor = "all the class names of your interceptor"> </plugin> </plugins>
The SQL statements in Dao er. xml related to the Dao layer do not need to be modified.
4. The front-end needs to display a page of parameters to the backend. After assembling the query parameters through the service layer, it submits them to MyBatis for querying the paging data. The data returned by the paging DAO interface I defined is a list, contains the paging query results. The front-end can use the jquery_pagination plug-in to display pages. Go to the official github to see how to set the pages.
<! -- The script required for pagination --> <% // obtain the request context 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 "> // The Action function handlePaginationClick (new_page _ Index, pagination_container) {<! -- Submit parameters of the current page from the stuForm form. You can use the restful method to allow springmvc to use the form parameters defined by the @ PathVariable keyword. These two parameters are provided by the paging control. We do not need to find them by ourselves, but the count starts from 0, while the background paging count starts from 1, so we need to manually add 1. --> $ ("# StuForm "). attr ("action", "Your defined paging query url/" + (new_page_index + 1); $ ("# stuForm "). submit (); return false ;}$ (function () {$ ("# News-Pagination "). pagination ($ {result. totalRecord}, {items_per_page :$ {result. pageSize}, // The number of records displayed per page current_page :$ {result. currentPage}-1, // Number of pages currently displayed num_display_entries: 8, // number of items displayed by PAGE next_text: "Next page", prev_text: "Previous Page", num_edge_entries: 2, // connect the pagination subject. The number of displayed items callback: handl EPaginationClick (id of the div on the current page), // The callback function load_first_page: false // prevents the page from being refreshed all the time (this is very important !) }) ;}); </Script> <! -- Use the c: forEach label to print the query result table --> <! -- Pagination Control name --> <div id = "News-Pagination"> </div>
The purpose of this summary is to form an overall solution for paging functions (both front-end and backend ). Starting from October 18 and May 18, I will write a small system that will use all of the Lessons Learned some time ago. After that, I will return to update the incorrect content in this article.
If you have any questions, please leave a message or go to the community on this site for discussion. Thank you for reading this article. Thank you for your support!