温馨提示:本文章是基于springboot 2.4.2 ,mybatis 2.2.0 来实现的。项目能正常使用并且已经项目中用了PageHelper插件的可以参考本文章。
(1)先建一个mybatis的配置类

/**
* @description: TODO MybatisConfig类 (加载PageHelper的配置之后加载该配置,添加拦截器,保证执行顺序。)
* @author zouyuxian
* @date 2021/12/1 15:26
*/
@Configuration
@AutoConfigureAfter(PageHelperAutoConfiguration.class)
public class MybatisConfig {
@Resource
SqlSessionFactoryiotSqlSessionFactory;
@PostConstruct
public void addInterceptor(){
iotSqlSessionFactory.getConfiguration().addInterceptor(new MybatisInterceptor());
iotSqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
}
}
(2)mybatis拦截类
@Component
@Slf4j
@Intercepts({
// @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),
@Signature(type = Executor.class, method ="query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }),
@Signature(type = Executor.class, method ="query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})
})
public class MybatisInterceptorimplements Interceptor {
private static final Loggerlogger = LoggerFactory.getLogger(MybatisInterceptor.class);
private static final IntegerMAPPED_STATEMENT_INDEX =0;
private static final IntegerPARAM_OBJ_INDEX =1;
private static final IntegerROW_BOUNDS_INDEX =2;
private static final IntegerRESULT_HANDLER_INDEX =3;
private static final IntegerCACHE_KEY_INDEX =4;
private static final IntegerBOUND_SQL_INDEX =5;
private static final StringCOUNT_PRE ="_COUNT";
@Override
public Object plugin(Object target) {
return Plugin.wrap(realTarget(target),this);
}
@Override
public void setProperties(Properties properties0) {
}
@SuppressWarnings("unchecked")
public static T realTarget(Object target) {
if (Proxy.isProxyClass(target.getClass())) {
MetaObject metaObject = SystemMetaObject.forObject(target);
return realTarget(metaObject.getValue("h.target"));
}
return (T) target;
}
@Override
public Object intercept(Invocation invocation)throws Throwable {
Object[] args = invocation.getArgs();
Object parameter = args[PARAM_OBJ_INDEX];
if(null==parameter){
return invocation.proceed();
}
PageBean pageBean = vaildParamter(parameter);
if(null==pageBean){
return invocation.proceed();
}
MappedStatement ms = (MappedStatement) args[MAPPED_STATEMENT_INDEX];
RowBounds rowBounds = (RowBounds) args[ROW_BOUNDS_INDEX];
ResultHandler resultHandler = (ResultHandler) args[RESULT_HANDLER_INDEX];
Executor executor = (Executor) invocation.getTarget();
CacheKey cacheKey;
BoundSql boundSql;
String newSql =null;
//由于逻辑关系,只会进入一次
if (args.length ==4) {
//四个参数走这里
boundSql = ms.getBoundSql(parameter);
cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);
//boundSql.getSql(),获取到sql之后,可以进行拼接修改
logger.info("四个参数的:"+newSql);
}else {
//六个参数走这里
cacheKey = (CacheKey) args[CACHE_KEY_INDEX];
boundSql = (BoundSql) args[BOUND_SQL_INDEX];
//boundSql.getSql(),获取到sql之后,可以进行拼接修改
logger.info("六个个参数的:"+newSql);
}
MappedStatement newMappedStatement = setCurrentSql(ms,parameter,boundSql,newSql);
args[MAPPED_STATEMENT_INDEX] = newMappedStatement;
return executor.query(newMappedStatement, parameter, rowBounds, resultHandler, cacheKey, boundSql);
}
/*
* @Description : 重新设置MappedStatement
@URL :
@param mappedStatement
@param paramObj
@param boundSql
@param sql
@return : org.apache.ibatis.mapping.MappedStatement
@Author : zouyuxian
@Date : 2021/12/24 12:41
**/
private MappedStatement setCurrentSql(MappedStatement mappedStatement, Object paramObj,BoundSql boundSql,String sql) {
BoundSqlSource boundSqlSource =new BoundSqlSource(boundSql);
MappedStatement newMappedStatement = copyFromMappedStatement(mappedStatement, boundSqlSource);
MetaObject metaObject = MetaObject.forObject(newMappedStatement,
new DefaultObjectFactory(),new DefaultObjectWrapperFactory(),
new DefaultReflectorFactory());
metaObject.setValue("sqlSource.boundSql.sql", sql);
return newMappedStatement;
}
/*
* @Description :获取MappedStatement
@URL :
@param invo
@return : org.apache.ibatis.mapping.MappedStatement
@Author : zouyuxian
@Date : 2021/12/24 12:41
**/
private MappedStatement getMappedStatement(Invocation invo) {
Object[] args = invo.getArgs();
Object mappedStatement = args[MAPPED_STATEMENT_INDEX];
return (MappedStatement) mappedStatement;
}
/*
* @Description : 自定义私有SqlSource
@Author : zouyuxian
@Date : 2021/12/24 12:42
**/
private class BoundSqlSourceimplements SqlSource {
private BoundSqlboundSql;
private BoundSqlSource(BoundSql boundSql) {
this.boundSql = boundSql;
}
@Override
public BoundSql getBoundSql(Object parameterObject) {
return boundSql;
}
}
/*
@Description :copyMappedStatement
@URL :
@param ms
@param newSqlSource
@return : org.apache.ibatis.mapping.MappedStatement
@Author : zouyuxian
@Date : 2021/12/24 12:42
**/
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 && ms.getKeyProperties().length >0) {
builder.keyProperty(ms.getKeyProperties()[0]);
}
builder.timeout(ms.getTimeout());
builder.parameterMap(ms.getParameterMap());
builder.resultMaps(ms.getResultMaps());
builder.resultSetType(ms.getResultSetType());
builder.cache(ms.getCache());
builder.flushCacheRequired(ms.isFlushCacheRequired());
builder.useCache(ms.isUseCache());
return builder.build();
}
3.总结,用了PageHelper插件,会先生成一个查询id_COUNT 的查询总数语句,先执行COUNT语句,然后才执行写的语句,在做这个的时候遇到重新setSql无效的问题,原先我是用的反射直接改boundSql的值,执行的sql还是原来的值,后来直接改的invocation[5]的值报了一个xxx_COUNT类型转换的错,最终查了很多文章和资料之后找到了解决方案:

参考文章指路:https://blog.csdn.net/zhuwei_clark/article/details/110958124