MybatisPlus自定义SQL日志打印

前言

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<String> 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<ParameterMapping> 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:
在这里插入图片描述

到这里,感谢您的浏览,如果您发现有需要更改之处,还恳请您能够指出来,再次感谢!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈橙橙丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值