Sql执行时间记录拦截器

直接上代码,自己看,粘贴可用

package com.example.demo.mybatis;

import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
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.session.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

/**
 * 描述:Sql执行时间记录拦截器 </br>
 * 作者:王林冲 </br>
 * 时间:2022-12-12 14:11
 */
@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})})
@Component
public class SqlExecuteTimeCountInterceptor implements Interceptor {

    private static Logger logger = LoggerFactory.getLogger(SqlExecuteTimeCountInterceptor.class);

    /**
     * 打印的参数字符串的最大长度
     */
    private final static int MAX_PARAM_LENGTH = 50;

    /**
     * 记录的最大SQL长度
     */
    private final static int MAX_SQL_LENGTH = 200;


    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object target = invocation.getTarget();
        long startTime = System.currentTimeMillis();
        StatementHandler statementHandler = (StatementHandler) target;
        try {
            return invocation.proceed();
        } finally {
            long endTime = System.currentTimeMillis();

            long timeCount = endTime - startTime;
            //获取BoundSql
            BoundSql boundSql = statementHandler.getBoundSql();
            //获取原始sql
            String sql = boundSql.getSql();
            Object parameterObject = boundSql.getParameterObject();
            List<ParameterMapping> parameterMappingList = boundSql.getParameterMappings();

            // 格式化Sql语句,去除换行符,替换参数
            sql = formatSQL(sql, parameterObject, parameterMappingList);

            logger.info("=======> 执行 SQL:{} 执行耗时 {} ms", sql, timeCount);

            PluginUtils.MPStatementHandler mpStatementHandler = PluginUtils.mpStatementHandler(statementHandler);
            List<String> paramList = handleParameterToStr(mpStatementHandler);
            String paramStr = String.join(", ", paramList);
            logger.info("=======> 条件参数:{}" ,paramStr );
        }
    }




    private List<Object> handleParameter(PluginUtils.MPStatementHandler mpSh) {
        List<Object> values = new ArrayList();
        Object parameterObject = mpSh.boundSql().getParameterObject();
        List<ParameterMapping> parameterMappings = mpSh.boundSql().getParameterMappings();
        if (parameterMappings != null) {
            Iterator var5 = parameterMappings.iterator();

            while(var5.hasNext()) {
                ParameterMapping parameterMapping = (ParameterMapping)var5.next();
                if (parameterMapping.getMode() != ParameterMode.OUT) {
                    String propertyName = parameterMapping.getProperty();
                    Object value;
                    if (mpSh.boundSql().hasAdditionalParameter(propertyName)) {
                        value = mpSh.boundSql().getAdditionalParameter(propertyName);
                    } else if (parameterObject == null) {
                        value = null;
                    } else if (mpSh.configuration().getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass())) {
                        value = parameterObject;
                    } else {
                        MetaObject metaObject = mpSh.configuration().newMetaObject(parameterObject);
                        value = metaObject.getValue(propertyName);
                    }

                    values.add(value);
                }
            }
        }
        return values;
    }

    private List<String> handleParameterToStr(PluginUtils.MPStatementHandler mpSh) {
        List<Object> objects = handleParameter(mpSh);
        List<String> values = new ArrayList<>(objects.size());
        objects.forEach(e -> {
            values.add(objToStr(e));
        });
        return values;
    }

    private String objToStr (Object o){
        StringBuffer sb  =new StringBuffer(o.toString());
        sb.append("(");
        sb.append(o.getClass().getSimpleName())   ;
        sb.append(")");
        String str = sb.toString();
        return str;
    }


    /**
     * 格式化/美化 SQL语句
     *
     * @param sql                  sql 语句
     * @param parameterObject      参数的Map
     * @param parameterMappingList 参数的List
     * @return 格式化之后的SQL
     */
    private String formatSQL(String sql, Object parameterObject, List<ParameterMapping> parameterMappingList) {
        // 输入sql字符串空判断
        if (sql == null || sql.length() == 0) {
            return "";
        }
        // 美化sql
        sql = beautifySql(sql);
        // 不传参数的场景,直接把sql美化一下返回出去
        if (parameterObject == null || parameterMappingList == null || parameterMappingList.size() == 0) {
            return sql;
        }
        return LimitSQLLength(sql);
    }



    /**
     * 返回限制长度之后的SQL语句
     *
     *
     * @param sql 原始SQL语句
     */
    private String LimitSQLLength(String sql) {
        if (sql == null || sql.length() == 0) {
            return "";
        }
        if (sql.length() > MAX_SQL_LENGTH) {
            return sql.substring(0, MAX_SQL_LENGTH);
        } else {
            return sql;
        }
    }


    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }



    /**
     * 替换SQL 中? 所对应的值, 只保留前50个字符
     *
     * @param sql     sql语句
     * @param valueOf ?对应的值
     */
    private String replaceValue(String sql, String valueOf) {
        //超过50个字符只取前50个
        if (valueOf != null && valueOf.length() > MAX_PARAM_LENGTH) {
            valueOf = valueOf.substring(0, MAX_PARAM_LENGTH);
        }
        sql = sql.replaceFirst("\\?", valueOf);
        return sql;
    }

    /**
     * 美化sql
     *
     * @param sql sql语句
     */
    private String beautifySql(String sql) {
        sql = sql.replaceAll("[\\s\n ]+", "  ");
        return sql;
    }
 }






作者:IT学习道场


欢迎关注微信公众号 : IT学习道场