On pagehelper Paging principle (rpm)

Before the project have been using the common element framework, the company recently set up a new framework for the project, primarily by the company's big brother built to springboot basis. In order to learn something, and I imitated him take a set of their own framework, but at the time of completion of pagination, really have a problem.

Paging component framework using pagehelper, I was already heard it, but also the first contact (ps: work 1, has been using the common element packaged front-end framework).

If you pagehelper, first maven project, to be introduced

<dependency>
   <groupId>com.github.pagehelper</groupId>
   <artifactId>pagehelper</artifactId>
   <version>4.1.6</version>
</dependency>

 

 

bootstrap front-end pagination plug-in, not repeat them here, straight to the point, persistence framework using a URL mybatis, pagination plug-in, point controller background,

@ResponseBody
@RequestMapping ( "/ TestPage")
public String TestPage (the HttpServletRequest Request) {
Page <PmProduct> Page PageUtil.pageStart = (Request);
List <PmProduct> = prodMapper.selectAll List ();
the JSONObject PageUtil.pageEnd RST = ( Request, Page, List);
return rst.toString ();
}
this is the controller code, then a question arises, why this query will be able to implement paging behind pageStart it? You can find out 10 pages of data you want, and get rid of it all, check out the 84 record.

With a problem, I started my trip to debug, first of all, I follow pageStart method, this category is the company's big brother PageUtil a package of tools, code is as follows:

public class PageUtil {

public enum CNT{
total,
res
}

public static <E> Page<E> pageStart(HttpServletRequest request){
return pageStart(request,null);
}

/ **
*
* @param Request
* @param page shows the number of the pageSize
* @param field names to be sorted orderBy written as: the product_id desc
* @return
* /
public static <E> Page <E> PageStart (Request the HttpServletRequest , String orderBy) {

int pageon=getPageon(request);
int pageSize=getpageSize(request);
Page<E> page=PageHelper.startPage(pageon, pageSize);
if(!StringUtils.isEmpty(orderBy)){
PageHelper.orderBy(orderBy);
}

return page;
}

private static int getPageon(HttpServletRequest request){
String pageonStr=request.getParameter("pageon");
int pageon;
if(StringUtils.isEmpty(pageonStr)){
pageon=1;
}else{
pageon=Integer.parseInt(pageonStr);
}
return pageon;
}

private static int getpageSize(HttpServletRequest request){
String pageSizeStr=request.getParameter("pageSize");
int pageSize;
if(StringUtils.isEmpty(pageSizeStr)){
pageSize=1;
}else{
pageSize=Integer.parseInt(pageSizeStr);
}
return pageSize;
}

/**
*
* @param request
* @param page
* @param list
* @param elName 页面显示所引用的变量名
*/
public static JSONObject pageEnd(HttpServletRequest request, Page<?> page,List<?> list){
JSONObject rstPage=new JSONObject();
rstPage.put(CNT.total.toString(), page.getTotal());
rstPage.put(CNT.res.toString(), list);
return rstPage;
}


}
Can see, pageStart there are two ways to reload, after entering the method to get the front page pageon passed, pageSize two parameters, namely the current page and the page shows how many, then call the PageHelper.startPage, then with into this method, find also a pair of method overloading, it does not matter, look down
/ **
* start page
*
* @param pageNum page
* @param pageSize page shows the number
* @param count whether to count queries
* @param reasonable pagination rationalization, when the default configuration with null
* @param pageSizeZero pageSize = 0 to true and all return a result, paging, by default configuration when null false
* /
public static <E> Page <E> StartPage (pageNum int, int the pageSize, Boolean COUNT, Reasonable Boolean, Boolean pageSizeZero) {
Page <E> = new new Page Page <E> (pageNum, the pageSize, COUNT);
page.setReasonable (Reasonable);
page.setPageSizeZero (pageSizeZero);
// has been performed when the orderBy when
Page <E> oldPage = SqlUtil.getLocalPage ( );
IF (! = null && oldPage oldPage.isOrderByOnly ()) {
page.setOrderBy (oldPage.getOrderBy ());
}
SqlUtil.setLocalPage (Page);
return Page;
}
The above method is where the real paging call, the original the assignment of the incoming parameters, assigned to the Page class, continue to find getLocalPage and setLoaclPage these two methods, very suspicious, follow up and see what he did in the end,

public static <T> Page<T> getLocalPage() {
return LOCAL_PAGE.get();
}

static void setLocalPage public (Page Page) {
LOCAL_PAGE.set (Page);
}
Private static Final the ThreadLocal <Page> = new new LOCAL_PAGE the ThreadLocal <Page> ();
Oh, little understood, but it was assigned to a thread-local variables stored inside, this is the story behind ThreadLocal, actually there are so powerful, so access to relevant blog link: https: //blog.csdn.net/u013521220/article/details/73604917, individuals simply understand the general idea is that this class has four methods, set, get, remove, initialValue, each thread can open an independent parameters independently of each other, which saves a copy of the variable current thread.

OK, then this place is to save the current variable parameters Page paging thread. There have assigned a value, then the paging process below, be sure which side of the page to get the parameters of this threadLocal.

Well, executing the startPage, the following is performed mybatis SQL statement,

<the SELECT the above mentioned id = "selectAll" resultMap = "BaseResultMap">
the SELECT SEQJD, PRODUCT_ID, PRODUCT_NAME, PRODUCT_DESC, CREATE_TIME, EFFECT_TIME,
expire_time, PRODUCT_STATUS, PROVINCE_CODE, REGION_CODE, CHANGE_TIME, OP_OPERATOR_ID,
PRODUCT_SYSTEM, PRODUCT_CODE
from PM_PRODUCT
</ the SELECT>
SQL statement is simple, is simply check out all the records PM_PRODUCT, that in the end is which side do intercept it? With this question, I follow the Code,

Discovery into mybatis of MapperPoxy the proxy class,

Invoke Object public (Object Proxy, Method, Method, Object [] args) {throws the Throwable
IF (Object.class.equals (method.getDeclaringClass ())) {
the try {
return Method.invoke (the this, args);
} the catch (the Throwable T) {
the throw ExceptionUtil.unwrapThrowable (T);
}
}
final MapperMethod mapperMethod = cachedMapperMethod (method);
return mapperMethod.execute (SQLSESSION, args);
}
execute method last executed again follow, enter the execute method of this class MapperMethod ,

public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
if (SqlCommandType.INSERT == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
} else if (SqlCommandType.UPDATE == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
} else if (SqlCommandType.DELETE == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
} else if (SqlCommandType.SELECT == command.getType()) {
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
} else if (SqlCommandType.FLUSH == command.getType()) {
result = sqlSession.flushStatements();
} else {
new new BindingException the throw ( "Unknown Method for Execution:" + command.getName ());
}
IF (Result == null && Method.getReturnType () isPrimitive () && method.returnsVoid ().!) {
the throw new new BindingException ( " Method Mapper ' "+ command.getName ()
+" attempted the return null from a to Method a with primitive return type ( "+ Method.getReturnType () +") ");.
}
return Result;
}
Since the select operation is performed and a number of inquiries, so to executeForMany this method, the latter continue to follow up the code SqlSessionTemplate, DefaultSqlSession (omitted), and finally can see the code entered invoke this method Plugin class,

Invoke Object public (Object Proxy, Method, Method, Object [] args) {throws the Throwable
the try {
the Set <Method,> = signatureMap.get Methods (method.getDeclaringClass ());
! IF (= null && methods.contains Methods (Method) ) {
return interceptor.intercept (the Invocation new new (target, Method, args));
}
return Method.invoke (target, args);
} the catch (Exception E) {
the throw ExceptionUtil.unwrapThrowable (E);
}
}
this time see , interceptor is mybatis interceptors, and PageHelper the interceptor class implements an interface, call intercept of these methods.

/ **
* Mybatis interceptor method
*
* @param Invocation interceptors into the reference
* @return returns an execution result
* @throws Throwable thrown
* /
public Object Intercept (the Invocation Invocation) throws the Throwable {
IF (autoRuntimeDialect) {
SqlUtil sqlUtil = getSqlUtil (Invocation);
return sqlUtil.processPage (Invocation);
} {the else
IF (autoDialect) {
initSqlUtil (Invocation);
}
return sqlUtil.processPage (Invocation);
}
}
/ **
* Mybatis interceptor method
*
* @param Invocation interceptors into the reference
* @return returns an execution result
* @throws Throwable thrown
* /
Private Object _processPage (the Invocation Invocation) throws the Throwable {
Object Final [] args = invocation.getArgs ();
Page Page = null;
// the supporting method parameters, will first attempt to acquire Page
IF (supportMethodsArguments) {
Page = the getPage (args);
}
// paging information
RowBounds rowBounds = ( RowBounds) args [2];
// the supporting method parameters, if it shows no page == null tab circumstances, no paging query
IF ((supportMethodsArguments && page == null)
// when not support paging parameter determination LocalPage and determining whether RowBounds paged
|| (supportMethodsArguments SqlUtil.getLocalPage && () == == null && RowBounds RowBounds.DEFAULT!)) {
return invocation.proceed ();
} {the else
does not support paging parameters //, page = = null, there needs to acquire
IF {(supportMethodsArguments Page == null &&!)
Page = the getPage (args);
}
return doProcessPage (Invocation, Page, args);
}
}
Eventually I found _processPage method SqlUtil in the middle, getPage this sentence, getLocalPage will save Page ThreadLocal variable in the take out, under all this at a glance,

 

Follow-up code and found entered doProcessPage method, by reflection, the total number of data query first, then the SQL tab assembly, MappedStatement of getBoundSql

public BoundSql getBoundSql(Object parameterObject) {
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings == null || parameterMappings.isEmpty()) {
boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
}

// check for nested result maps in parameter mappings (issue #30)
for (ParameterMapping pm : boundSql.getParameterMappings()) {
String rmId = pm.getResultMapId();
if (rmId != null) {
ResultMap rm = configuration.getResultMap(rmId);
if (rm != null) {
hasNestedResultMaps |= rm.hasNestedResultMaps();
}
}
}

boundSql return;
}
continue to follow the code found, the final tab query, transferred getPageBoundSql PageStaticSqlSource class,

BoundSql getPageBoundSql protected (Object parameterObject) {
String tempSql = SQL;
String PageHelper.getOrderBy orderBy = ();
IF (orderBy = null!) {
tempSql = OrderByParser.converToOrderBySql (SQL, orderBy);
}
tempSql localParser.get = (). getPageSql (tempSql);
return new new BoundSql (Configuration, tempSql, localParser.get () getPageParameterMapping (Configuration, original.getBoundSql (parameterObject)), parameterObject.);
}
enters getPageSql this method, found OracleParser into the class (and many other Parser, for different database),

String getPageSql public (String SQL) {
the StringBuilder sqlBuilder the StringBuilder new new = (sql.length () + 120);
sqlBuilder.append (. "SELECT * from (SELECT * tmp_page, rownum row_id from (");
sqlBuilder.append (SQL) ;
sqlBuilder.append ( ") tmp_page the wHERE rownum <=) the wHERE row_id?>?");
return sqlBuilder.toString ();
}
finally, the original pagination SQL is pieced together here.
Summary: Save parameters PageHelper first passed to the front page of this object, then a copy of the page stored in the ThreadLoacl, so it can ensure pagination when parameters independently of each other, and then use the interceptors mybatis provided, made of ThreadLocal value, re-assembled paging SQL, complete pagination.

PS: DEBUG with good or bad, to see the source code framework is very great impact.


----------------
Disclaimer: This article is CSDN blogger "King of the Hammers DW3 'original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source and this link statement.
Original link: https: //blog.csdn.net/qq_21996541/article/details/79796117

Guess you like

Origin www.cnblogs.com/muxi0407/p/11988718.html