mybatis-config.xml
里配置自己家实现拦截器MyBatisUpdateInterceptor
<plugins>
<plugin interceptor="project.x.interceptor.MyBatisUpdateInterceptor"/>
</plugins>
applicationContext.xml
里配置自己家实现拦截器的包路径
<context:component-scan base-package="project" >
<context:exclude-filter type="regex" expression="project.x.interceptor.*"/>
</context:component-scan>
<context:component-scan base-package=“project”>:
这行配置告诉 Spring 框架从指定的 base-package(在这个例子中是 project 包)中扫描和识别 Spring 组件(例如 @Component、@Service、@Repository、@Controller 等注解的类)。
通过这个配置,Spring 会自动检测和注册这些类为 Spring 的 Bean,无需手动在配置文件中定义它们。
1.<context:exclude-filter type="regex" expression="project.x.interceptor.*"/>
:
这个配置是用来排除某些类不被 Spring 的组件扫描机制识别和注册为 Bean。
type=“regex” 表示使用正则表达式来匹配要排除的类。
expression=“project.x.interceptor.*” 指定了匹配的正则表达式,意思是 project.x.interceptor 包及其子包中的所有类都不会被 Spring 的组件扫描机制识别和注册为 Bean。
2.<context:exclude-filter type="regex" expression="project.x.interceptor.*"/>
:
这个配置是用来排除某些类不被 Spring 的组件扫描机制识别和注册为 Bean。
type=“regex” 表示使用正则表达式来匹配要排除的类。
expression=“project.x.interceptor.*” 指定了匹配的正则表达式,意思是 project.x.interceptor 包及其子包中的所有类都不会被 Spring 的组件扫描机制识别和注册为 Bean。
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.Statement;
import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import org.apache.commons.collections.CollectionUtils;
import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.util.ReflectionUtils;
import project.common.core.logging.Logger;
import project.common.core.logging.Logger.Level;
@Intercepts({
@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
,@Signature(type = ResultSetHandler.class, method="handleResultSets", args ={Statement.class})
})
public class MyBatisUpdateInterceptor implements Interceptor {
private static Logger logger = Logger.getLogger(MyBatisUpdateInterceptor.class);
private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
private static final ReflectorFactory REFLECTOR_FACTORY = new DefaultReflectorFactory();
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object target = invocation.getTarget();
if (target instanceof StatementHandler) {
return dealStatementHandler(invocation);
} else if (target instanceof ResultSetHandler) {
return dealResultSetHandler(invocation);
}
return invocation.proceed();
}
private Object dealStatementHandler(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
BoundSql boundSql = statementHandler.getBoundSql();
MetaObject metaResultSetHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, REFLECTOR_FACTORY);
MappedStatement mappedStatement = (MappedStatement) metaResultSetHandler.getValue("delegate.mappedStatement");
String sqlId = mappedStatement.getId();
String sqlCommandType = mappedStatement.getSqlCommandType().toString();
if ("SELECT".equals(sqlCommandType)) {
Configuration configuration = mappedStatement.getConfiguration(); // 获取节点的配置
String sql = showSql(configuration, boundSql); // 获取到最终的sql语句
logger.log(Level.INFO,sqlId +"\t"+ sql);
return invocation.proceed();
}
return invocation.proceed();
}
public static String showSql(Configuration configuration, BoundSql boundSql) {
// 获取参数
Object parameterObject = boundSql.getParameterObject();
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
// sql语句中多个空格都用一个空格代替
String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
if (CollectionUtils.isNotEmpty(parameterMappings) && parameterObject != null) {
// 获取类型处理器注册器,类型处理器的功能是进行java类型和数据库类型的转换
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
// 如果根据parameterObject.getClass()可以找到对应的类型,则替换
if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
sql = sql.replaceFirst("\\?",Matcher.quoteReplacement(getParameterValue(parameterObject)));
} else {
// MetaObject主要是封装了originalObject对象,提供了get和set的方法用于获取和设置originalObject的属性值,主要支持对JavaBean、Collection、Map三种类型对象的操作
MetaObject metaObject = configuration.newMetaObject(parameterObject);
for (ParameterMapping parameterMapping : parameterMappings) {
String propertyName = parameterMapping.getProperty();
if (metaObject.hasGetter(propertyName)) {
Object obj = metaObject.getValue(propertyName);
sql = sql.replaceFirst("\\?",
Matcher.quoteReplacement(getParameterValue(obj)));
} else if (boundSql.hasAdditionalParameter(propertyName)) {
// 该分支是动态sql
Object obj = boundSql.getAdditionalParameter(propertyName);
sql = sql.replaceFirst("\\?",
Matcher.quoteReplacement(getParameterValue(obj)));
} else {
// 未知参数,替换?防止错位
sql = sql.replaceFirst("\\?", "unknown");
}
}
}
}
return sql;
}
private static String getParameterValue(Object obj) {
String value;
if (obj instanceof String) {
value = "'" + obj.toString() + "'";
} else if (obj instanceof Date) {
DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT,DateFormat.DEFAULT, Locale.CHINA);
value = "'" + formatter.format(new Date()) + "'";
} else {
if (obj != null) {
value = obj.toString();
} else {
value = "";
}
}
return value;
}