Mybatis commonly USES paging plug ins to implement quick paging handling techniques

  • 2020-05-10 18:13:07
  • OfStack

Before you share the execution code for the entire query paging, take a look at the 1 execution process.

1. Generally speaking, it USES the plug-in interceptor of mybatis to intercept before the execution of sql, adding limit X X to the query statement

2. Use one Page object throughout the execution process. This Page object needs to write the front-end paging component in Java

3. This paging architecture is supported by a relatively complete set of three-tier entity, dao and service

4. Some of the helper classes used in this page

Note: there is a lot of content to share, so I will not list the required jar11. When you use this paging function, you can go to the jar package at night to find out what you lack. You can import the maven package as much as possible, because maven can reduce version conflicts and other good advantages.

All I can say is that I want you to use this pagination function as quickly as possible. If you don't understand it, please add me QQ1 to discuss 1063150576. Don't spray ha! There is also the article may be relatively large, but take some time, read it and practice 1 next 1 will be a lot.

Step 1: since the theme is around how to page, we will start from mybatis, first of all, we put the mybatis related to two of the more important the configuration file out and do a brief understanding of the one is mybatis - config xml, another one is entity corresponding mapper configuration files, I will write a comment on the configuration file, 1 see you will understand.

mybatis-config.xml


<!DOCTYPE configuration 
PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-config.dtd"> 
<configuration> 
<!--  Global parameters  --> 
<settings> 
<!--  Enable or disable caching with the global mapper.  --> 
<setting name="cacheEnabled" value="false"/> 
<!--  Enable or disable lazy loading globally. When disabled, all associated objects are loaded instantly.  --> 
<setting name="lazyLoadingEnabled" value="true"/> 
<!--  When enabled, objects with lazy-loaded properties will be fully loaded with arbitrary properties when invoked. Otherwise, each property will be loaded as needed.  --> 
<setting name="aggressiveLazyLoading" value="true"/> 
<!--  Whether to allow single sql  Returns multiple data sets  ( Depends on driver compatibility ) default:true --> 
<setting name="multipleResultSetsEnabled" value="true"/> 
<!--  Whether column aliases can be used  ( Depends on driver compatibility ) default:true --> 
<setting name="useColumnLabel" value="true"/> 
<!--  allow JDBC  Generate the primary key. Drive support is required. If I set it to true , this setting will force the use of the generated primary key, yes 1 Some drives are not compatible but can still be executed.  default:false --> 
<setting name="useGeneratedKeys" value="false"/> 
<!--  The specified  MyBatis  How to map automatically   The columns of the base table  NONE : no: PARTIAL: Part of the  FULL: all  --> 
<setting name="autoMappingBehavior" value="PARTIAL"/> 
<!--  This is the default execution type   ( SIMPLE:  Simple;  REUSE:  The actuator may be reused prepared statements Statements; BATCH:  The executor can repeatedly execute statements and batch updates.)  --> 
<setting name="defaultExecutorType" value="SIMPLE"/> 
<!--  Convert the fields using the hump nominature.  --> 
<setting name="mapUnderscoreToCamelCase" value="true"/> 
<!--  Set the local cache range  session: There will be data sharing  statement: Scope statement  ( So there's no sharing of data  ) defalut:session --> 
<setting name="localCacheScope" value="SESSION"/> 
<!--  Set up but JDBC The type is null time , Certain drivers   To specify a value ,default:OTHER , you do not need to specify the type when inserting a null value  --> 
<setting name="jdbcTypeForNull" value="NULL"/> 
<setting name="logPrefix" value="dao."/> 
</settings> 
<!-- A nickname is 1 A shorter Java  Name of type  --> 
<typeAliases> 
<typeAlias type="com.store.base.model.StoreUser" 
alias="User"></typeAlias> 
<typeAlias type="com.store.base.secondmodel.pratice.model.Product" 
alias="Product"></typeAlias> 
<typeAlias type="com.store.base.secondmodel.base.Page" 
alias="Page"></typeAlias> 
</typeAliases> 
<!--  The plug-in configuration , This way to mybatis Configure the page blocker, which we need to implement ourselves  --> 
<plugins> 
<plugin interceptor="com.store.base.secondmodel.base.pageinterceptor.PaginationInterceptor" /> 
</plugins> 
</configuration>

One ProductMapper.xml is used as a test object, and this mapper file simply configures1 query statement that needs to be used


<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > 
<mapper namespace="com.store.base.secondmodel.pratice.dao.ProductDao" > 
<sql id="baseColumns" > 
id, product_name as productName, product_no as productNo, price as price 
</sql> 
<select id="findList" resultType="com.store.base.secondmodel.pratice.model.Product"> 
select <include refid="baseColumns"/> from t_store_product 
</select> 
</mapper>

Step 2: the following is an in-depth analysis of the page blocker, with the following classes and their corresponding interfaces

(1) BaseInterceptor interceptor base class

(2) PaginationInterceptor, the paging plug-in class we are going to use, inherits the above base class

(3) SQLHelper is mainly used to execute count statement in advance, and also to obtain the entire paging statement

(4) Dialect, MysqlDialect, mainly used for whether the database supports limit statements, and then encapsulate the complete limit statements

The following are a few of these Shared presentations

BaseInterceptor.java


package com.store.base.secondmodel.base.pageinterceptor; 
import java.io.Serializable; 
import java.util.Properties; 
import org.apache.ibatis.logging.Log; 
import org.apache.ibatis.logging.LogFactory; 
import org.apache.ibatis.plugin.Interceptor; 
import com.store.base.secondmodel.base.Global; 
import com.store.base.secondmodel.base.Page; 
import com.store.base.secondmodel.base.dialect.Dialect; 
import com.store.base.secondmodel.base.dialect.MySQLDialect; 
import com.store.base.util.Reflections; 
/** 
* Mybatis Page blocker base class  
* @author yiyong_wu 
* 
*/ 
public abstract class BaseInterceptor implements Interceptor, Serializable { 
private static final long serialVersionUID = 1L; 
protected static final String PAGE = "page"; 
protected static final String DELEGATE = "delegate"; 
protected static final String MAPPED_STATEMENT = "mappedStatement"; 
protected Log log = LogFactory.getLog(this.getClass()); 
protected Dialect DIALECT; 
/** 
*  The parameters are converted and checked  
* @param parameterObject  Parameter object  
* @param page  Paging object  
* @return  Paging object  
* @throws NoSuchFieldException  Parameter not found  
*/ 
@SuppressWarnings("unchecked") 
protected static Page<Object> convertParameter(Object parameterObject, Page<Object> page) { 
try{ 
if (parameterObject instanceof Page) { 
return (Page<Object>) parameterObject; 
} else { 
return (Page<Object>)Reflections.getFieldValue(parameterObject, PAGE); 
} 
}catch (Exception e) { 
return null; 
} 
} 
/** 
*  Set properties, support custom dialect classes and the way you configure your database  
* <code>dialectClass</code>, Custom dialect class. You don't have to configure this  
* <ode>dbms</ode>  Database type, database supported by the plug-in  
* <code>sqlPattern</code>  To intercept SQL ID 
* @param p  attribute  
*/ 
protected void initProperties(Properties p) { 
Dialect dialect = null; 
String dbType = Global.getConfig("jdbc.type"); 
if("mysql".equals(dbType)){ 
dialect = new MySQLDialect(); 
} 
if (dialect == null) { 
throw new RuntimeException("mybatis dialect error."); 
} 
DIALECT = dialect; 
} 
}

PaginationInterceptor.java


package com.store.base.secondmodel.base.pageinterceptor; 
import java.util.Properties; 
import org.apache.ibatis.executor.Executor; 
import org.apache.ibatis.mapping.BoundSql; 
import org.apache.ibatis.mapping.MappedStatement; 
import org.apache.ibatis.mapping.SqlSource; 
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.MetaObject; 
import org.apache.ibatis.session.ResultHandler; 
import org.apache.ibatis.session.RowBounds; 
import com.store.base.secondmodel.base.Page; 
import com.store.base.secondmodel.base.util.StringUtils; 
import com.store.base.util.Reflections; 
/** 
*  Database paging plug-in that intercepts only query statements . 
* @author yiyong_wu 
* 
*/ 
@Intercepts({ @Signature(type = Executor.class, method = "query", args = { 
MappedStatement.class, Object.class, RowBounds.class, 
ResultHandler.class }) }) 
public class PaginationInterceptor extends BaseInterceptor { 
private static final long serialVersionUID = 1L; 
@Override 
public Object intercept(Invocation invocation) throws Throwable { 
final MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; 
Object parameter = invocation.getArgs()[1]; 
BoundSql boundSql = mappedStatement.getBoundSql(parameter); 
Object parameterObject = boundSql.getParameterObject(); 
//  Gets the paging parameter object  
Page<Object> page = null; 
if (parameterObject != null) { 
page = convertParameter(parameterObject, page); 
} 
//  Paging occurs if the paging object is set  
if (page != null && page.getPageSize() != -1) { 
if (StringUtils.isBlank(boundSql.getSql())) { 
return null; 
} 
String originalSql = boundSql.getSql().trim(); 
//  You get the total number of records  
page.setCount(SQLHelper.getCount(originalSql, null,mappedStatement, parameterObject, boundSql, log)); 
//  Paging query   Localized object   Modify the database note the change implementation  
String pageSql = SQLHelper.generatePageSql(originalSql, page,DIALECT); 
invocation.getArgs()[2] = new RowBounds(RowBounds.NO_ROW_OFFSET,RowBounds.NO_ROW_LIMIT); 
BoundSql newBoundSql = new BoundSql( 
mappedStatement.getConfiguration(), pageSql, 
boundSql.getParameterMappings(), 
boundSql.getParameterObject()); 
//  To solve MyBatis  paging foreach  Parameters of the failure  start 
if (Reflections.getFieldValue(boundSql, "metaParameters") != null) { 
MetaObject mo = (MetaObject) Reflections.getFieldValue( 
boundSql, "metaParameters"); 
Reflections.setFieldValue(newBoundSql, "metaParameters", mo); 
} 
//  To solve MyBatis  paging foreach  Parameters of the failure  end 
MappedStatement newMs = copyFromMappedStatement(mappedStatement,new BoundSqlSqlSource(newBoundSql)); 
invocation.getArgs()[0] = newMs; 
} 
return invocation.proceed(); 
} 
@Override 
public Object plugin(Object target) { 
return Plugin.wrap(target, this); 
} 
@Override 
public void setProperties(Properties properties) { 
super.initProperties(properties); 
} 
private MappedStatement copyFromMappedStatement(MappedStatement ms, 
SqlSource newSqlSource) { 
MappedStatement.Builder builder = new MappedStatement.Builder( 
ms.getConfiguration(), ms.getId(), newSqlSource, 
ms.getSqlCommandType()); 
builder.resource(ms.getResource()); 
builder.fetchSize(ms.getFetchSize()); 
builder.statementType(ms.getStatementType()); 
builder.keyGenerator(ms.getKeyGenerator()); 
if (ms.getKeyProperties() != null) { 
for (String keyProperty : ms.getKeyProperties()) { 
builder.keyProperty(keyProperty); 
} 
} 
builder.timeout(ms.getTimeout()); 
builder.parameterMap(ms.getParameterMap()); 
builder.resultMaps(ms.getResultMaps()); 
builder.cache(ms.getCache()); 
return builder.build(); 
} 
public static class BoundSqlSqlSource implements SqlSource { 
BoundSql boundSql; 
public BoundSqlSqlSource(BoundSql boundSql) { 
this.boundSql = boundSql; 
} 
@Override 
public BoundSql getBoundSql(Object parameterObject) { 
return boundSql; 
} 
} 
}

SQLHelper.java


package com.store.base.secondmodel.base.pageinterceptor; 
import java.sql.Connection; 
import java.sql.PreparedStatement; 
import java.sql.ResultSet; 
import java.sql.SQLException; 
import java.util.List; 
import java.util.regex.Matcher; 
import java.util.regex.Pattern; 
import org.apache.ibatis.executor.ErrorContext; 
import org.apache.ibatis.executor.ExecutorException; 
import org.apache.ibatis.logging.Log; 
import org.apache.ibatis.mapping.BoundSql; 
import org.apache.ibatis.mapping.MappedStatement; 
import org.apache.ibatis.mapping.ParameterMapping; 
import org.apache.ibatis.mapping.ParameterMode; 
import org.apache.ibatis.reflection.MetaObject; 
import org.apache.ibatis.reflection.property.PropertyTokenizer; 
import org.apache.ibatis.scripting.xmltags.ForEachSqlNode; 
import org.apache.ibatis.session.Configuration; 
import org.apache.ibatis.type.TypeHandler; 
import org.apache.ibatis.type.TypeHandlerRegistry; 
import com.store.base.secondmodel.base.Global; 
import com.store.base.secondmodel.base.Page; 
import com.store.base.secondmodel.base.dialect.Dialect; 
import com.store.base.secondmodel.base.util.StringUtils; 
import com.store.base.util.Reflections; 
/** 
* SQL Utility class  
* @author yiyong_wu 
* 
*/ 
public class SQLHelper { 
/** 
*  Default private constructor  
*/ 
private SQLHelper() { 
} 
/** 
*  right SQL parameter (?) Set the value , reference org.apache.ibatis.executor.parameter.DefaultParameterHandler 
* 
* @param ps  Stands for precompiled  SQL  The object of the statement.  
* @param mappedStatement MappedStatement 
* @param boundSql SQL 
* @param parameterObject  Parameter object  
* @throws java.sql.SQLException  Database exception  
*/ 
@SuppressWarnings("unchecked") 
public static void setParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql, Object parameterObject) throws SQLException { 
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId()); 
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); 
if (parameterMappings != null) { 
Configuration configuration = mappedStatement.getConfiguration(); 
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); 
MetaObject metaObject = parameterObject == null ? null : 
configuration.newMetaObject(parameterObject); 
for (int i = 0; i < parameterMappings.size(); i++) { 
ParameterMapping parameterMapping = parameterMappings.get(i); 
if (parameterMapping.getMode() != ParameterMode.OUT) { 
Object value; 
String propertyName = parameterMapping.getProperty(); 
PropertyTokenizer prop = new PropertyTokenizer(propertyName); 
if (parameterObject == null) { 
value = null; 
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { 
value = parameterObject; 
} else if (boundSql.hasAdditionalParameter(propertyName)) { 
value = boundSql.getAdditionalParameter(propertyName); 
} else if (propertyName.startsWith(ForEachSqlNode.ITEM_PREFIX) && boundSql.hasAdditionalParameter(prop.getName())) { 
value = boundSql.getAdditionalParameter(prop.getName()); 
if (value != null) { 
value = configuration.newMetaObject(value).getValue(propertyName.substring(prop.getName().length())); 
} 
} else { 
value = metaObject == null ? null : metaObject.getValue(propertyName); 
} 
@SuppressWarnings("rawtypes") 
TypeHandler typeHandler = parameterMapping.getTypeHandler(); 
if (typeHandler == null) { 
throw new ExecutorException("There was no TypeHandler found for parameter " + propertyName + " of statement " + mappedStatement.getId()); 
} 
typeHandler.setParameter(ps, i + 1, value, parameterMapping.getJdbcType()); 
} 
} 
} 
} 
/** 
*  Query the total number of records  
* @param sql SQL statements  
* @param connection  Database connection  
* @param mappedStatement mapped 
* @param parameterObject  parameter  
* @param boundSql boundSql 
* @return  The total number of records  
* @throws SQLException sql Query error  
*/ 
public static int getCount(final String sql, final Connection connection, 
final MappedStatement mappedStatement, final Object parameterObject, 
final BoundSql boundSql, Log log) throws SQLException { 
String dbName = Global.getConfig("jdbc.type"); 
final String countSql; 
if("oracle".equals(dbName)){ 
countSql = "select count(1) from (" + sql + ") tmp_count"; 
}else{ 
countSql = "select count(1) from (" + removeOrders(sql) + ") tmp_count"; 
} 
Connection conn = connection; 
PreparedStatement ps = null; 
ResultSet rs = null; 
try { 
if (log.isDebugEnabled()) { 
log.debug("COUNT SQL: " + StringUtils.replaceEach(countSql, new String[]{"\n","\t"}, new String[]{" "," "})); 
} 
if (conn == null){ 
conn = mappedStatement.getConfiguration().getEnvironment().getDataSource().getConnection(); 
} 
ps = conn.prepareStatement(countSql); 
BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), countSql, 
boundSql.getParameterMappings(), parameterObject); 
// To solve MyBatis  paging foreach  Parameters of the failure  start 
if (Reflections.getFieldValue(boundSql, "metaParameters") != null) { 
MetaObject mo = (MetaObject) Reflections.getFieldValue(boundSql, "metaParameters"); 
Reflections.setFieldValue(countBS, "metaParameters", mo); 
} 
// To solve MyBatis  paging foreach  Parameters of the failure  end 
SQLHelper.setParameters(ps, mappedStatement, countBS, parameterObject); 
rs = ps.executeQuery(); 
int count = 0; 
if (rs.next()) { 
count = rs.getInt(1); 
} 
return count; 
} finally { 
if (rs != null) { 
rs.close(); 
} 
if (ps != null) { 
ps.close(); 
} 
if (conn != null) { 
conn.close(); 
} 
} 
} 
/** 
*  Generate specific pages based on the database dialect sql 
* @param sql Mapper In the Sql statements  
* @param page  Paging object  
* @param dialect  Dialect type  
* @return  paging SQL 
*/ 
public static String generatePageSql(String sql, Page<Object> page, Dialect dialect) { 
if (dialect.supportsLimit()) { 
return dialect.getLimitString(sql, page.getFirstResult(), page.getMaxResults()); 
} else { 
return sql; 
} 
} 
/** 
*  Get rid of qlString the select Clause.  
* @param hql 
* @return 
*/ 
@SuppressWarnings("unused") 
private static String removeSelect(String qlString){ 
int beginPos = qlString.toLowerCase().indexOf("from"); 
return qlString.substring(beginPos); 
} 
/** 
*  Get rid of hql the orderBy Clause.  
* @param hql 
* @return 
*/ 
private static String removeOrders(String qlString) { 
Pattern p = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE); 
Matcher m = p.matcher(qlString); 
StringBuffer sb = new StringBuffer(); 
while (m.find()) { 
m.appendReplacement(sb, ""); 
} 
m.appendTail(sb); 
return sb.toString(); 
} 
}

Dialect java interface


package com.store.base.secondmodel.base.dialect; 
/** 
*  similar hibernate the Dialect, But only the paging part is pared down  
* @author yiyong_wu 
* 
*/ 
public interface Dialect { 
/** 
*  Whether the database itself supports paging the current paging query mode  
*  Database paging is not performed if the database does not support it  
* 
* @return true : supports the current paging query mode  
*/ 
public boolean supportsLimit(); 
/** 
*  will sql Convert to paging SQL , calling paging respectively sql 
* 
* @param sql SQL statements  
* @param offset  The Numbers of the  
* @param limit  How many records are displayed per page  
* @return  Paged query sql 
*/ 
public String getLimitString(String sql, int offset, int limit); 
}

MySQLDialect.java


package com.store.base.secondmodel.base.dialect; 
/** 
* Mysql Realization of dialect  
* @author yiyong_wu 
* 
*/ 
public class MySQLDialect implements Dialect { 
@Override 
public boolean supportsLimit() { 
return true; 
} 
@Override 
public String getLimitString(String sql, int offset, int limit) { 
return getLimitString(sql, offset, Integer.toString(offset),Integer.toString(limit)); 
} 
/** 
*  will sql Become a paging sql statements , To provide the offset and limit Use placeholder symbols (placeholder) replace . 
* <pre> 
*  Such as mysql 
* dialect.getLimitString("select * from user", 12, ":offset",0,":limit")  Will return  
* select * from user limit :offset,:limit 
* </pre> 
* 
* @param sql  The actual SQL statements  
* @param offset  The number of entries is recorded at the beginning of the page  
* @param offsetPlaceholder  Pagination starts recording the number of bars - placeholder symbol  
* @param limitPlaceholder  Paging the number of record bar placeholders  
* @return  Pagination that contains placeholders sql 
*/ 
public String getLimitString(String sql, int offset, String offsetPlaceholder, String limitPlaceholder) { 
StringBuilder stringBuilder = new StringBuilder(sql); 
stringBuilder.append(" limit "); 
if (offset > 0) { 
stringBuilder.append(offsetPlaceholder).append(",").append(limitPlaceholder); 
} else { 
stringBuilder.append(limitPlaceholder); 
} 
return stringBuilder.toString(); 
} 
}

We've almost finished sharing how to implement the whole block pagination here, but we still have more important tasks to do. If we want the whole thing to run, we must have some basic work to do. Next, we will analyze the whole Page object and the 3-layer architecture it is based on, and we will use product as the entity for analysis. 1. The whole set of 3-layer architecture will bring you a full harvest. We go from entity- > dao- > Let's do service in that order.

First, we inherit two abstract entity classes BaseEntity and DataEntity for our entity

BaseEntity.java mainly places Page member variable, which can be inherited by every entity


package com.store.base.secondmodel.base; 
import java.io.Serializable; 
import java.util.Map; 
import javax.xml.bind.annotation.XmlTransient; 
import org.apache.commons.lang3.StringUtils; 
import org.apache.commons.lang3.builder.ReflectionToStringBuilder; 
import com.fasterxml.jackson.annotation.JsonIgnore; 
import com.google.common.collect.Maps; 
import com.store.base.model.StoreUser; 
/** 
*  At the top of the Entity 
* @author yiyong_wu 
* 
* @param <T> 
*/ 
public abstract class BaseEntity<T> implements Serializable { 
private static final long serialVersionUID = 1L; 
/** 
*  Delete tag ( 0 : normal; 1 : delete; 2 : review;)  
*/ 
public static final String DEL_FLAG_NORMAL = "0"; 
public static final String DEL_FLAG_DELETE = "1"; 
public static final String DEL_FLAG_AUDIT = "2"; 
/** 
*  Entity number (only 1 Logo)  
*/ 
protected String id; 
/** 
*  The current user  
*/ 
protected StoreUser currentUser; 
/** 
*  The current entity paging object  
*/ 
protected Page<T> page; 
/** 
*  The custom SQL ( SQL Logo, SQL Content)  
*/ 
private Map<String, String> sqlMap; 
public BaseEntity() { 
} 
public BaseEntity(String id) { 
this(); 
this.id = id; 
} 
public String getId() { 
return id; 
} 
public void setId(String id) { 
this.id = id; 
} 
/** 
*  This is mainly aimed at shiro It is called when an insert update is performed to get the current user  
* @return 
*/ 
@JsonIgnore 
@XmlTransient 
public StoreUser getCurrentUser() { 
if(currentUser == null){ 
// currentUser = UserUtils.getUser(); 
} 
return currentUser; 
} 
public void setCurrentUser(StoreUser currentUser) { 
this.currentUser = currentUser; 
} 
@JsonIgnore 
@XmlTransient 
public Page<T> getPage() { 
if (page == null){ 
page = new Page<>(); 
} 
return page; 
} 
public Page<T> setPage(Page<T> page) { 
this.page = page; 
return page; 
} 
@JsonIgnore 
@XmlTransient 
public Map<String, String> getSqlMap() { 
if (sqlMap == null){ 
sqlMap = Maps.newHashMap(); 
} 
return sqlMap; 
} 
public void setSqlMap(Map<String, String> sqlMap) { 
this.sqlMap = sqlMap; 
} 
/** 
*  Execute method before insertion, subclass implementation  
*/ 
public abstract void preInsert(); 
/** 
*  Execute method before update, subclass implementation  
*/ 
public abstract void preUpdate(); 
/** 
*  Is it a new record (default: false ), the call setIsNewRecord() Set a new record and use customizations ID .  
*  Set to true After forcing the insert statement, ID It will not be generated automatically and will be passed in manually.  
* @return 
*/ 
public boolean getIsNewRecord() { 
return StringUtils.isBlank(getId()); 
} 
/** 
*  Global variable object  
*/ 
@JsonIgnore 
public Global getGlobal() { 
return Global.getInstance(); 
} 
/** 
*  Get the database name  
*/ 
@JsonIgnore 
public String getDbName(){ 
return Global.getConfig("jdbc.type"); 
} 
@Override 
public String toString() { 
return ReflectionToStringBuilder.toString(this); 
} 
}

DataEntity.java, mainly stores the update and delete time, creates users, updates users, logically removes flags, etc


package com.store.base.secondmodel.base; 
import java.util.Date; 
import org.hibernate.validator.constraints.Length; 
import com.fasterxml.jackson.annotation.JsonFormat; 
import com.fasterxml.jackson.annotation.JsonIgnore; 
import com.store.base.model.StoreUser; 
/** 
*  data Entity 
* @author yiyong_wu 
* 
* @param <T> 
*/ 
public abstract class DataEntity<T> extends BaseEntity<T> { 
private static final long serialVersionUID = 1L; 
protected StoreUser createBy; //  The creator  
protected Date createDate; //  Creation date  
protected StoreUser updateBy; //  Update the  
protected Date updateDate; //  Updated date  
protected String delFlag; //  Delete tag ( 0 : normal; 1 : delete; 2 Review:)  
public DataEntity() { 
super(); 
this.delFlag = DEL_FLAG_NORMAL; 
} 
public DataEntity(String id) { 
super(id); 
} 
/** 
*  The method is executed before insertion and needs to be called manually  
*/ 
@Override 
public void preInsert() { 
//  Don't limit ID for UUID , the call setIsNewRecord() Use customization ID 
// User user = UserUtils.getUser(); 
// if (StringUtils.isNotBlank(user.getId())) { 
// this.updateBy = user; 
// this.createBy = user; 
// } 
this.updateDate = new Date(); 
this.createDate = this.updateDate; 
} 
/** 
*  The method is executed before updating and needs to be called manually  
*/ 
@Override 
public void preUpdate() { 
// User user = UserUtils.getUser(); 
// if (StringUtils.isNotBlank(user.getId())) { 
// this.updateBy = user; 
// } 
this.updateDate = new Date(); 
} 
// @JsonIgnore 
public StoreUser getCreateBy() { 
return createBy; 
} 
public void setCreateBy(StoreUser createBy) { 
this.createBy = createBy; 
} 
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 
public Date getCreateDate() { 
return createDate; 
} 
public void setCreateDate(Date createDate) { 
this.createDate = createDate; 
} 
// @JsonIgnore 
public StoreUser getUpdateBy() { 
return updateBy; 
} 
public void setUpdateBy(StoreUser updateBy) { 
this.updateBy = updateBy; 
} 
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 
public Date getUpdateDate() { 
return updateDate; 
} 
public void setUpdateDate(Date updateDate) { 
this.updateDate = updateDate; 
} 
@JsonIgnore 
@Length(min = 1, max = 1) 
public String getDelFlag() { 
return delFlag; 
} 
public void setDelFlag(String delFlag) { 
this.delFlag = delFlag; 
} 
}

Product java product class


package com.store.base.secondmodel.pratice.model; 
import com.store.base.secondmodel.base.DataEntity; 
/** 
* Product base  
*2016 years 10 month 11 day  
*yiyong_wu 
*/ 
public class Product extends DataEntity<Product>{ 
private static final long serialVersionUID = 1L; 
private String productName; 
private float price; 
private String productNo; 
public String getProductName() { 
return productName; 
} 
public void setProductName(String productName) { 
this.productName = productName; 
} 
public float getPrice() { 
return price; 
} 
public void setPrice(float price) { 
this.price = price; 
} 
public String getProductNo() { 
return productNo; 
} 
public void setProductNo(String productNo) { 
this.productNo = productNo; 
} 
}

How about, you know, you see a very complicated one entity inheritance connection, but what does it matter? The more complex the more complete it will be. Next I'll look at the dao layer, which is also the third layer. Get ready for the baptism

BaseDao.java reserved interface


<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > 
<mapper namespace="com.store.base.secondmodel.pratice.dao.ProductDao" > 
<sql id="baseColumns" > 
id, product_name as productName, product_no as productNo, price as price 
</sql> 
<select id="findList" resultType="com.store.base.secondmodel.pratice.model.Product"> 
select <include refid="baseColumns"/> from t_store_product 
</select> 
</mapper>
0

ProductDao. java mybatis corresponding interface mapper is also the implementation of dao, which requires a customized annotation @MyBatisRepository


<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > 
<mapper namespace="com.store.base.secondmodel.pratice.dao.ProductDao" > 
<sql id="baseColumns" > 
id, product_name as productName, product_no as productNo, price as price 
</sql> 
<select id="findList" resultType="com.store.base.secondmodel.pratice.model.Product"> 
select <include refid="baseColumns"/> from t_store_product 
</select> 
</mapper>
1

Custom annotations MyBatisRepository.java, related to custom annotations, not too much reading here, 1 pile of online materials


<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > 
<mapper namespace="com.store.base.secondmodel.pratice.dao.ProductDao" > 
<sql id="baseColumns" > 
id, product_name as productName, product_no as productNo, price as price 
</sql> 
<select id="findList" resultType="com.store.base.secondmodel.pratice.model.Product"> 
select <include refid="baseColumns"/> from t_store_product 
</select> 
</mapper>
2

Note: the ProductMapper.xml file is more closely related to ProductDao.java. You can see that the namespace of the configuration file above points to the path of dao.

Then we go to the final service analysis, which is 1 sample or 3 layer inheritance

BaseService.java


package com.store.base.secondmodel.base; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.transaction.annotation.Transactional; 
/** 
* Service The top-level parent class  
* @author yiyong_wu 
* 
*/ 
@Transactional(readOnly = true) 
public abstract class BaseService { 
// For logging  
protected Logger logger = LoggerFactory.getLogger(getClass()); 
}

CrudService.java add, delete, change and check the relevant business interface implementation


<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > 
<mapper namespace="com.store.base.secondmodel.pratice.dao.ProductDao" > 
<sql id="baseColumns" > 
id, product_name as productName, product_no as productNo, price as price 
</sql> 
<select id="findList" resultType="com.store.base.secondmodel.pratice.model.Product"> 
select <include refid="baseColumns"/> from t_store_product 
</select> 
</mapper>
4

ProductService.java, to inherit the CrudService interface, note the injection of dao and entity type 1 schema


<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > 
<mapper namespace="com.store.base.secondmodel.pratice.dao.ProductDao" > 
<sql id="baseColumns" > 
id, product_name as productName, product_no as productNo, price as price 
</sql> 
<select id="findList" resultType="com.store.base.secondmodel.pratice.model.Product"> 
select <include refid="baseColumns"/> from t_store_product 
</select> 
</mapper>
5

I want to see the comrades here getting impatient. But if you miss the next one, basically see is almost equal to white to see just now, the victory of the revolution in the second half, because the entire paging is around 1 Page object, the content of the blockbuster is finally out, when you fill the Page object onto the BaseEntity just now, you will find 1 cutting is complete, please donate, said Page object is as follows


<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > 
<mapper namespace="com.store.base.secondmodel.pratice.dao.ProductDao" > 
<sql id="baseColumns" > 
id, product_name as productName, product_no as productNo, price as price 
</sql> 
<select id="findList" resultType="com.store.base.secondmodel.pratice.model.Product"> 
select <include refid="baseColumns"/> from t_store_product 
</select> 
</mapper>
6

After looking at this Page object, I think it's a little bit of a feel for it, and then I'm just going to post a little bit about the utility class that I'm using, and I'm just going to say a little bit about the utility class, so you can get your own code and read it.

PropertiesLoader.java is used to get the constant configuration file under the resource folder


<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > 
<mapper namespace="com.store.base.secondmodel.pratice.dao.ProductDao" > 
<sql id="baseColumns" > 
id, product_name as productName, product_no as productNo, price as price 
</sql> 
<select id="findList" resultType="com.store.base.secondmodel.pratice.model.Product"> 
select <include refid="baseColumns"/> from t_store_product 
</select> 
</mapper>
7

Global.java is used to get some global constants, which can be read from the configuration file or defined as final static, by calling the above class to get the configuration file.


package com.store.base.secondmodel.base; 
import java.io.File; 
import java.io.IOException; 
import java.util.Map; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.core.io.DefaultResourceLoader; 
import com.google.common.collect.Maps; 
import com.store.base.secondmodel.base.util.PropertiesLoader; 
import com.store.base.secondmodel.base.util.StringUtils; 
/** 
*  Global configuration class  
* @author yiyong_wu 
* 
*/ 
public class Global { 
private static final Logger logger = LoggerFactory.getLogger(Global.class); 
/** 
*  Current object instance  
*/ 
private static Global global = new Global(); 
/** 
*  Save the global property value  
*/ 
private static Map<String, String> map = Maps.newHashMap(); 
/** 
*  The properties file loads the object  
*/ 
private static PropertiesLoader loader = new PropertiesLoader("application.properties"); 
/** 
*  According to / hidden  
public static final String SHOW = "1"; 
public static final String HIDE = "0"; 
/** 
*  is / no  
*/ 
public static final String YES = "1"; 
public static final String NO = "0"; 
/** 
*  state   on / Under the  app special  
*/ 
public static final String UPSHVELF = "1"; 
public static final String DOWNSHVELF = "2"; 
public static final String SEPARATOR = "/"; 
/** 
*  right / wrong  
*/ 
public static final String TRUE = "true"; 
public static final String FALSE = "false"; 
/** 
*  Upload file base virtual path  
*/ 
public static final String USERFILES_BASE_URL = "/userfiles/"; 
/** 
*  For a rich text editor, the ending will be empty div 
*/ 
public static final String ENDS = "<p><br></p>"; 
/** 
*  Default empty private constructor  
*/ 
public Global() { 
//do nothing in this method,just empty 
} 
/** 
*  Gets the current object instance  
*/ 
public static Global getInstance() { 
return global; 
} 
/** 
*  Access to the configuration  
*/ 
public static String getConfig(String key) { 
String value = map.get(key); 
if (value == null){ 
value = loader.getProperty(key); 
map.put(key, value != null ? value : StringUtils.EMPTY); 
} 
return value; 
} 
/** 
*  To obtain URL The suffix  
*/ 
public static String getUrlSuffix() { 
return getConfig("urlSuffix"); 
} 
/** 
*  Page gets constant  
* @see ${fns:getConst('YES')} 
*/ 
public static Object getConst(String field) { 
try { 
return Global.class.getField(field).get(null); 
} catch (Exception e) { 
logger.error(" Error getting constants ", e); 
} 
return null; 
} 
/** 
*  Obtain engineering path  
* @return 
*/ 
public static String getProjectPath(){ 
//  If the project path is configured, it is returned directly, otherwise it is automatically fetched.  
String projectPath = Global.getConfig("projectPath"); 
if (StringUtils.isNotBlank(projectPath)){ 
return projectPath; 
} 
try { 
File file = new DefaultResourceLoader().getResource("").getFile(); 
if (file != null){ 
while(true){ 
File f = new File(file.getPath() + File.separator + "src" + File.separator + "main"); 
if (f == null || f.exists()){ 
break; 
} 
if (file.getParentFile() != null){ 
file = file.getParentFile(); 
}else{ 
break; 
} 
} 
projectPath = file.toString(); 
} 
} catch (IOException e) { 
logger.error(" Failed to load configuration file ", e); 
} 
return projectPath; 
} 
}

CookieUtil.java is known by its name as a utility class for getting and storing cookie


<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > 
<mapper namespace="com.store.base.secondmodel.pratice.dao.ProductDao" > 
<sql id="baseColumns" > 
id, product_name as productName, product_no as productNo, price as price 
</sql> 
<select id="findList" resultType="com.store.base.secondmodel.pratice.model.Product"> 
select <include refid="baseColumns"/> from t_store_product 
</select> 
</mapper>
9

SpringContextHolder.java is mainly used to get the current ApplicationContext in the java code, which needs to be configured in the spring configuration file and lazily loaded to false.


package com.store.base.secondmodel.base.util; 
import org.apache.commons.lang3.Validate; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.beans.factory.DisposableBean; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.ApplicationContextAware; 
import org.springframework.context.annotation.Lazy; 
import org.springframework.stereotype.Service; 
@Service 
@Lazy(false) 
public class SpringContextHolder implements ApplicationContextAware, 
DisposableBean { 
private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class); 
private static ApplicationContext applicationContext = null; 
/** 
*  Gets the value stored in a static variable ApplicationContext. 
*/ 
public static ApplicationContext getApplicationContext() { 
assertContextInjected(); 
return applicationContext; 
} 
/** 
*  From static variables applicationContext in Bean,  Automatically converts to the type of the assigned object . 
*/ 
@SuppressWarnings("unchecked") 
public static <T> T getBean(String name) { 
assertContextInjected(); 
return (T) applicationContext.getBean(name); 
} 
/** 
*  From static variables applicationContext in Bean,  Automatically converts to the type of the assigned object . 
*/ 
public static <T> T getBean(Class<T> requiredType) { 
assertContextInjected(); 
return applicationContext.getBean(requiredType); 
} 
@Override 
public void destroy() throws Exception { 
SpringContextHolder.clearHolder(); 
} 
/** 
*  implementation ApplicationContextAware interface ,  injection Context Into a static variable . 
*/ 
@Override 
public void setApplicationContext(ApplicationContext applicationContext) { 
logger.debug(" injection ApplicationContext to SpringContextHolder:{}", applicationContext); 
SpringContextHolder.applicationContext = applicationContext; 
if (SpringContextHolder.applicationContext != null) { 
logger.info("SpringContextHolder In the ApplicationContext Be overwritten ,  The original ApplicationContext for :" + SpringContextHolder.applicationContext); 
} 
} 
/** 
*  remove SpringContextHolder In the ApplicationContext for Null. 
*/ 
public static void clearHolder() { 
if (logger.isDebugEnabled()){ 
logger.debug(" remove SpringContextHolder In the ApplicationContext:" + applicationContext); 
} 
applicationContext = null; 
} 
/** 
*  check ApplicationContext Don't empty . 
*/ 
private static void assertContextInjected() { 
Validate.validState(applicationContext != null, "applicaitonContext Property not injected ,  please applicationContext.xml Defined in the SpringContextHolder."); 
} 
}

StringUtils. java string related 1 utility class


package com.store.base.secondmodel.base.util; 
import java.io.UnsupportedEncodingException; 
import java.util.Locale; 
import java.util.regex.Matcher; 
import java.util.regex.Pattern; 
import javax.servlet.http.HttpServletRequest; 
import org.apache.commons.lang3.StringEscapeUtils; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.web.context.request.RequestContextHolder; 
import org.springframework.web.context.request.ServletRequestAttributes; 
import org.springframework.web.servlet.LocaleResolver; 
import com.store.base.util.Encodes; 
/** 
*  String help class  
* @author yiyong_wu 
* 
*/ 
public class StringUtils extends org.apache.commons.lang3.StringUtils { 
private static final char SEPARATOR = '_'; 
private static final String CHARSET_NAME = "UTF-8"; 
private static final Logger logger = LoggerFactory.getLogger(StringUtils.class); 
/** 
*  Convert to a byte array  
* @param str 
* @return 
*/ 
public static byte[] getBytes(String str){ 
if (str != null){ 
try { 
return str.getBytes(CHARSET_NAME); 
} catch (UnsupportedEncodingException e) { 
logger.error("", e); 
return new byte[0]; 
} 
}else{ 
return new byte[0]; 
} 
} 
/** 
*  Convert to a byte array  
* @param str 
* @return 
*/ 
public static String toString(byte[] bytes){ 
try { 
return new String(bytes, CHARSET_NAME); 
} catch (UnsupportedEncodingException e) { 
logger.error("", e); 
return EMPTY; 
} 
} 
/** 
*  Does it contain a string  
* @param str  Validate string  
* @param strs  String group  
* @return  Contains the return true 
*/ 
public static boolean inString(String str, String... strs){ 
if (str != null){ 
for (String s : strs){ 
if (str.equals(trim(s))){ 
return true; 
} 
} 
} 
return false; 
} 
/** 
*  replace HTML Labeling method  
*/ 
public static String replaceHtml(String html) { 
if (isBlank(html)){ 
return ""; 
} 
String regEx = "<.+?>"; 
Pattern p = Pattern.compile(regEx); 
Matcher m = p.matcher(html); 
return m.replaceAll(""); 
} 
/** 
*  Replace it with one that the phone recognizes HTML , remove the styles and attributes, and leave the carriage return.  
* @param html 
* @return 
*/ 
public static String replaceMobileHtml(String html){ 
if (html == null){ 
return ""; 
} 
return html.replaceAll("<([a-z]+?)\\s+?.*?>", "<$1>"); 
} 
/** 
*  Replace it with one that the phone recognizes HTML , remove the styles and attributes, and leave the carriage return.  
* @param txt 
* @return 
*/ 
public static String toHtml(String txt){ 
if (txt == null){ 
return ""; 
} 
return replace(replace(Encodes.escapeHtml(txt), "\n", "<br/>"), "\t", " "); 
} 
/** 
*  Thumbnail string (Chinese and English characters are not distinguished)  
* @param str  Target string  
* @param length  Intercept length  
* @return 
*/ 
public static String abbr(String str, int length) { 
if (str == null) { 
return ""; 
} 
try { 
StringBuilder sb = new StringBuilder(); 
int currentLength = 0; 
for (char c : replaceHtml(StringEscapeUtils.unescapeHtml4(str)).toCharArray()) { 
currentLength += String.valueOf(c).getBytes("GBK").length; 
if (currentLength <= length - 3) { 
sb.append(c); 
} else { 
sb.append("..."); 
break; 
} 
} 
return sb.toString(); 
} catch (UnsupportedEncodingException e) { 
logger.error("", e); 
} 
return ""; 
} 
/** 
*  convert Double type  
*/ 
public static Double toDouble(Object val){ 
if (val == null){ 
return 0D; 
} 
try { 
return Double.valueOf(trim(val.toString())); 
} catch (Exception e) { 
logger.error("", e); 
return 0D; 
} 
} 
/** 
*  convert Float type  
*/ 
public static Float toFloat(Object val){ 
return toDouble(val).floatValue(); 
} 
/** 
*  convert Long type  
*/ 
public static Long toLong(Object val){ 
return toDouble(val).longValue(); 
} 
/** 
*  convert Integer type  
*/ 
public static Integer toInteger(Object val){ 
return toLong(val).intValue(); 
} 
/** 
*  To obtain i18n string  
*/ 
public static String getMessage(String code, Object[] args) { 
LocaleResolver localLocaleResolver = SpringContextHolder.getBean(LocaleResolver.class); 
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest(); 
Locale localLocale = localLocaleResolver.resolveLocale(request); 
return SpringContextHolder.getApplicationContext().getMessage(code, args, localLocale); 
} 
/** 
*  Get the user remote address  
*/ 
public static String getRemoteAddr(HttpServletRequest request){ 
String remoteAddr = request.getHeader("X-Real-IP"); 
if (isNotBlank(remoteAddr)) { 
remoteAddr = request.getHeader("X-Forwarded-For"); 
} 
if (isNotBlank(remoteAddr)) { 
remoteAddr = request.getHeader("Proxy-Client-IP"); 
} 
if (isNotBlank(remoteAddr)) { 
remoteAddr = request.getHeader("WL-Proxy-Client-IP"); 
} 
return remoteAddr != null ? remoteAddr : request.getRemoteAddr(); 
} 
/** 
*  Hump nomenclature tool  
* @return 
* toCamelCase("hello_world") == "helloWorld" 
* toCapitalizeCamelCase("hello_world") == "HelloWorld" 
* toUnderScoreCase("helloWorld") = "hello_world" 
*/ 
public static String toCamelCase(String s) { 
String s1 =s; 
if (s1 == null) { 
return null; 
} 
s1 = s.toLowerCase(); 
StringBuilder sb = new StringBuilder(s1.length()); 
boolean upperCase = false; 
for (int i = 0; i < s1.length(); i++) { 
char c = s1.charAt(i); 
if (c == SEPARATOR) { 
upperCase = true; 
} else if (upperCase) { 
sb.append(Character.toUpperCase(c)); 
upperCase = false; 
} else { 
sb.append(c); 
} 
} 
return sb.toString(); 
} 
/** 
*  Hump nomenclature tool  
* @return 
* toCamelCase("hello_world") == "helloWorld" 
* toCapitalizeCamelCase("hello_world") == "HelloWorld" 
* toUnderScoreCase("helloWorld") = "hello_world" 
*/ 
public static String toCapitalizeCamelCase(String s) { 
String s1 = s; 
if (s1 == null) { 
return null; 
} 
s1 = toCamelCase(s1); 
return s1.substring(0, 1).toUpperCase() + s1.substring(1); 
} 
/** 
*  Hump nomenclature tool  
* @return 
* toCamelCase("hello_world") == "helloWorld" 
* toCapitalizeCamelCase("hello_world") == "HelloWorld" 
* toUnderScoreCase("helloWorld") = "hello_world" 
*/ 
public static String toUnderScoreCase(String s) { 
if (s == null) { 
return null; 
} 
StringBuilder sb = new StringBuilder(); 
boolean upperCase = false; 
for (int i = 0; i < s.length(); i++) { 
char c = s.charAt(i); 
boolean nextUpperCase = true; 
if (i < (s.length() - 1)) { 
nextUpperCase = Character.isUpperCase(s.charAt(i + 1)); 
} 
if ((i > 0) && Character.isUpperCase(c)) { 
if (!upperCase || !nextUpperCase) { 
sb.append(SEPARATOR); 
} 
upperCase = true; 
} else { 
upperCase = false; 
} 
sb.append(Character.toLowerCase(c)); 
} 
return sb.toString(); 
} 
/** 
*  convert JS Gets the object value and generates 3 The object operation returns the result  
* @param objectString  The object list  
*  Such as: row.user.id 
*  Returns: !row?'':!row.user?'':!row.user.id?'':row.user.id 
*/ 
public static String jsGetVal(String objectString){ 
StringBuilder result = new StringBuilder(); 
StringBuilder val = new StringBuilder(); 
String[] vals = split(objectString, "."); 
for (int i=0; i<vals.length; i++){ 
val.append("." + vals[i]); 
result.append("!"+(val.substring(1))+"?'':"); 
} 
result.append(val.substring(1)); 
return result.toString(); 
} 
}

With these basics in mind, you can simply write a control-layer interface and see that one page object is returned at a time, with a list of query objects encapsulated inside, and the list is paginated.


package com.store.controller; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.ResponseBody; 
import org.springframework.web.bind.annotation.RestController; 
import com.store.base.secondmodel.base.Page; 
import com.store.base.secondmodel.pratice.model.Product; 
import com.store.base.secondmodel.pratice.service.ProductService; 
/** 
*TODO 
*2016 years 10 month 11 day  
*yiyong_wu 
*/ 
@RestController 
@RequestMapping("/product") 
public class ProductController { 
@Autowired 
private ProductService productService; 
@ResponseBody 
@RequestMapping(value="/getPageProduct") 
public Page<Product> getPageProduct(HttpServletRequest request,HttpServletResponse response){ 
Page<Product> page = productService.findPage(new Page<Product>(request,response), new Product()); 
return page; 
} 
}

Finally, let's take a look at how the page object is used by the page, so that we have a complete introduction to the pagination function, which is a lot of code, but very complete.


package com.store.base.secondmodel.base.pageinterceptor; 
import java.io.Serializable; 
import java.util.Properties; 
import org.apache.ibatis.logging.Log; 
import org.apache.ibatis.logging.LogFactory; 
import org.apache.ibatis.plugin.Interceptor; 
import com.store.base.secondmodel.base.Global; 
import com.store.base.secondmodel.base.Page; 
import com.store.base.secondmodel.base.dialect.Dialect; 
import com.store.base.secondmodel.base.dialect.MySQLDialect; 
import com.store.base.util.Reflections; 
/** 
* Mybatis Page blocker base class  
* @author yiyong_wu 
* 
*/ 
public abstract class BaseInterceptor implements Interceptor, Serializable { 
private static final long serialVersionUID = 1L; 
protected static final String PAGE = "page"; 
protected static final String DELEGATE = "delegate"; 
protected static final String MAPPED_STATEMENT = "mappedStatement"; 
protected Log log = LogFactory.getLog(this.getClass()); 
protected Dialect DIALECT; 
/** 
*  The parameters are converted and checked  
* @param parameterObject  Parameter object  
* @param page  Paging object  
* @return  Paging object  
* @throws NoSuchFieldException  Parameter not found  
*/ 
@SuppressWarnings("unchecked") 
protected static Page<Object> convertParameter(Object parameterObject, Page<Object> page) { 
try{ 
if (parameterObject instanceof Page) { 
return (Page<Object>) parameterObject; 
} else { 
return (Page<Object>)Reflections.getFieldValue(parameterObject, PAGE); 
} 
}catch (Exception e) { 
return null; 
} 
} 
/** 
*  Set properties, support custom dialect classes and the way you configure your database  
* <code>dialectClass</code>, Custom dialect class. You don't have to configure this  
* <ode>dbms</ode>  Database type, database supported by the plug-in  
* <code>sqlPattern</code>  To intercept SQL ID 
* @param p  attribute  
*/ 
protected void initProperties(Properties p) { 
Dialect dialect = null; 
String dbType = Global.getConfig("jdbc.type"); 
if("mysql".equals(dbType)){ 
dialect = new MySQLDialect(); 
} 
if (dialect == null) { 
throw new RuntimeException("mybatis dialect error."); 
} 
DIALECT = dialect; 
} 
}
3

Here is basically the entire paging function described more clearly, I hope to help you quickly solve the problem of paging, of course, to display beautiful paging in the front end to do 1 for li css style what, finally bless you can quickly master the paging function!


Related articles: