前言
mybatisplus在mybatis的基础上为我们提供了诸多方便,大大加快了开发的速率,但是在日常工作中,还是会发现有一些不方便之处,那就是关于日志的打印,框架虽然也提供了日志打印,但是日志的排版等还是没有特别直观,这里我们自定义来实现sql的打印格式。 本篇文章的内容主要是将原本打印格式中分开显示的 ? 和 参数列表整合到SQL中,方便我们在进行错误追踪时省去填入参数,提高效率
创建SQL拦截器package com.pig4cloud.pig.common.mybatis.config;
import com.baomidou.mybatisplus.core.enums.IEnum;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler;
import lombok.extern.slf4j.Slf4j;
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.ParameterMode;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @author chenxh
* @date 2021/3/31
*/
@Slf4j
@Intercepts({@Signature(
type = StatementHandler.class,
method = "query",
args = {Statement.class, ResultHandler.class}
), @Signature(
type = StatementHandler.class,
method = "update",
args = {Statement.class}
), @Signature(
type = StatementHandler.class,
method = "batch",
args = {Statement.class}
)})
public class MybatisSqlInterceptor extends AbstractSqlParserHandler implements Interceptor {
/**
* 获取配置中需要拦截的表,自定义配置,逗号隔开
*/
@Value("#{'${tmall.sync.tables:}'.split(',')}")
private List tableNames;
/**
* 忽略插入sql_log表的语句
*/
private static final String IGNORE_SQL_PREFIX = "insert into sql_log";
@Override
public Object intercept(Invocation invocation) throws Throwable {
if (CollectionUtils.isEmpty(tableNames)) {
return invocation.proceed();
}
StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
String sql = boundSql.getSql().replaceAll("\\s+", " ").toLowerCase();
if (sql.toLowerCase(Locale.ENGLISH).startsWith(IGNORE_SQL_PREFIX)) {
return invocation.proceed();
}
List parameterMappings = new ArrayList(boundSql.getParameterMappings());
Object parameterObject = boundSql.getParameterObject();
if (parameterMappings.isEmpty() && parameterObject == null) {
log.warn("parameterMappings is empty or parameterObject is null");
return invocation.proceed();
}
Configuration configuration = mappedStatement.getConfiguration();
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
try {
this.sqlParser(metaObject);
String parameter = "null";
MetaObject newMetaObject = configuration.newMetaObject(parameterObject);
for (ParameterMapping parameterMapping : parameterMappings) {
if (parameterMapping.getMode() == ParameterMode.OUT) {
continue;
}
String propertyName = parameterMapping.getProperty();
if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
parameter = getParameterValue(parameterObject);
} else if (newMetaObject.hasGetter(propertyName)) {
parameter = getParameterValue(newMetaObject.getValue(propertyName));
} else if (boundSql.hasAdditionalParameter(propertyName)) {
parameter = getParameterValue(boundSql.getAdditionalParameter(propertyName));
}
sql = sql.replaceFirst("\\?", parameter);
}
log.info("===========EXECUTE SQL===========");
log.info("------> "+ sql);
log.info("===========EXECUTE END===========");
// 将拦截到的sql语句插入日志表中
} catch (Exception e) {
log.error(String.format("intercept sql error: [%s]", sql), e);
}
return invocation.proceed();
}
/**
* 获取参数
*
* @param param Object类型参数
* @return 转换之后的参数
*/
private static String getParameterValue(Object param) {
if (param == null) {
return "null";
}
if (param instanceof Number) {
return param.toString();
}
String value = null;
if (param instanceof String) {
value = param.toString();
} else if (param instanceof Date) {
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((Date) param);
} else if (param instanceof IEnum) {
value = String.valueOf(((IEnum) param).getValue());
} else {
value = param.toString();
}
return StringUtils.quotaMark(value);
}
@Override
public Object plugin(Object o) {
if (o instanceof StatementHandler) {
return Plugin.wrap(o, this);
}
return o;
}
@Override
public void setProperties(Properties properties) {
}
}
进行注入,交由spring来统一管理
@Configuration(proxyBeanMethods = false)
public class MybatisAutoConfiguration implements WebMvcConfigurer {
/**
* 自定义sql打印格式
* @return
*/
@Bean
public MybatisSqlInterceptor performanceInterceptor() {
return new MybatisSqlInterceptor();
}
}
只需要如上两个步骤即可,代码可以直接使用,我就便可以实现SQL的自定义格式,在这里我将sql的参数直接替换到了sql语句中,这样更方便我们日常查看以及debug的使用。
以下便是sql:
到这里,感谢您的浏览,如果您发现有需要更改之处,还恳请您能够指出来,再次感谢!