packagecn.com.common.page;importjava.sql.Connection;importjava.sql.PreparedStatement;importjava.sql.ResultSet;importjava.sql.SQLException;importjava.util.List;importjava.util.regex.Matcher;importjava.util.regex.Pattern;importorg.apache.ibatis.cache.CacheKey;importorg.apache.ibatis.executor.BatchResult;importorg.apache.ibatis.executor.ErrorContext;importorg.apache.ibatis.executor.Executor;importorg.apache.ibatis.executor.ExecutorException;importorg.apache.ibatis.mapping.BoundSql;importorg.apache.ibatis.mapping.MappedStatement;importorg.apache.ibatis.mapping.ParameterMapping;importorg.apache.ibatis.mapping.ParameterMode;importorg.apache.ibatis.reflection.MetaObject;importorg.apache.ibatis.session.Configuration;importorg.apache.ibatis.session.ResultHandler;importorg.apache.ibatis.session.RowBounds;importorg.apache.ibatis.transaction.Transaction;importorg.apache.ibatis.type.TypeHandler;importorg.apache.ibatis.type.TypeHandlerRegistry;public class PageExecutor implementsExecutor {privateExecutor executor;privateString pattern;publicPageExecutor(Executor executor, String pattern) {this.executor =executor;this.pattern =pattern;
}
@Overridepublic int update(MappedStatement ms, Object parameter) throwsSQLException {returnexecutor.update(ms, parameter);
}
@Overridepublic Listquery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler,
CacheKey cacheKey, BoundSql boundSql)throwsSQLException {
RowBounds rb= newRowBounds(rowBounds.getOffset(), rowBounds.getLimit());
List rows =executor.query(ms, parameter, rowBounds, resultHandler,
cacheKey, boundSql);returnpageResolver(rows, ms, parameter, rb);
}/*** 修改返回值类型
*@paramrows
*@paramms
*@paramparameter
*@paramrowBounds
*@return
*/
private List pageResolver(Listrows, MappedStatement ms,
Object parameter, RowBounds rowBounds) {
String msid=ms.getId();//如果需要分页查询,修改返回类型为Page对象
if(msid.matches(pattern)) {int count =getCount(ms, parameter);int offset =rowBounds.getOffset();int pagesize =rowBounds.getLimit();return new Page(offset/pagesize + 1, pagesize, count, rows);
}returnrows;
}/*** 获取总数
*@paramms
*@paramparameter
*@return
*/
private intgetCount(MappedStatement ms, Object parameter) {
BoundSql bsql=ms.getBoundSql(parameter);
String sql=bsql.getSql();
String countSql=getCountSql(sql);
Connection connection= null;
PreparedStatement stmt= null;
ResultSet rs= null;try{
connection=ms.getConfiguration().getEnvironment().getDataSource()
.getConnection();
stmt=connection.prepareStatement(countSql);
setParameters(stmt, ms, bsql, parameter);
rs=stmt.executeQuery();if(rs.next())return rs.getInt(1);
}catch(SQLException e) {
e.printStackTrace();
}finally{try{if (connection != null && !connection.isClosed()) {
connection.close();
}
}catch(SQLException e) {
e.printStackTrace();
}
}return 0;
}
@SuppressWarnings("unchecked")private voidsetParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql,
Object parameterObject)throwsSQLException {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
List 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();if (parameterObject == null) {
value= null;
}else if(typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value=parameterObject;
}else if(boundSql.hasAdditionalParameter(propertyName)) {
value=boundSql.getAdditionalParameter(propertyName);
}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());
}
}
}
}privateString getCountSql(String sql) {
String countHql= " SELECT count(*) "
+removeSelect(removeOrders(sql));returncountHql;
}protectedString removeOrders(String sql) {
Pattern p= Pattern.compile("ORDER\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE);
Matcher m=p.matcher(sql);
StringBuffer sb= newStringBuffer();while(m.find()) {
m.appendReplacement(sb,"");
}
m.appendTail(sb);returnsb.toString();
}//去除sql语句中select子句
private staticString removeSelect(String hql) {int beginPos = hql.toLowerCase().indexOf("from");if (beginPos < 0) {throw new IllegalArgumentException(" hql : " + hql + " must has a keyword 'from'");
}returnhql.substring(beginPos);
}
@Overridepublic Listquery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler)throwsSQLException {
BoundSql boundSql=ms.getBoundSql(parameter);returnquery(ms, parameter, rowBounds, resultHandler,
executor.createCacheKey(ms, parameter, rowBounds, boundSql),
boundSql);
}
@Overridepublic List flushStatements() throwsSQLException {returnexecutor.flushStatements();
}
@Overridepublic void commit(boolean required) throwsSQLException {
executor.commit(required);
}
@Overridepublic void rollback(boolean required) throwsSQLException {
executor.rollback(required);
}
@OverridepublicCacheKey createCacheKey(MappedStatement ms, Object parameterObject,
RowBounds rowBounds, BoundSql boundSql) {returnexecutor
.createCacheKey(ms, parameterObject, rowBounds, boundSql);
}
@Overridepublic booleanisCached(MappedStatement ms, CacheKey key) {returnexecutor.isCached(ms, key);
}
@Overridepublic voidclearLocalCache() {
executor.clearLocalCache();
}
@Overridepublic voiddeferLoad(MappedStatement ms, MetaObject resultObject,
String property, CacheKey key, Class>targetType) {
executor.deferLoad(ms, resultObject, property, key, targetType);
}
@OverridepublicTransaction getTransaction() {returnexecutor.getTransaction();
}
@Overridepublic void close(booleanforceRollback) {
executor.close(forceRollback);
}
@Overridepublic booleanisClosed() {returnexecutor.isClosed();
}
}