liurunyu
2025-05-21 4242128e8980734889a01a1ac429393b51073894
重新设计mybatis插件实现方式,增加输出sql日志插件
1个文件已修改
2个文件已添加
249 ■■■■■ 已修改文件
pms-parent/pms-common/src/main/java/com/dy/common/mybatis/MyBatisConfig.java 63 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pms-parent/pms-common/src/main/java/com/dy/common/mybatis/PrintSqlHelp.java 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pms-parent/pms-common/src/main/java/com/dy/common/mybatis/PrintSqlInterceptor.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pms-parent/pms-common/src/main/java/com/dy/common/mybatis/MyBatisConfig.java
@@ -4,27 +4,70 @@
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import jakarta.annotation.PostConstruct;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@org.springframework.context.annotation.Configuration
import java.util.List;
@Configuration
public class MyBatisConfig {
    @Autowired
    private List<SqlSessionFactory> sqlSessionFactoryList;
    @Value("${mybatis-plus.configuration.print-sql}")
    private boolean printSql;
    /**
     * 两个拦截器,自动生成ID,异常时输出SQL
     */
    @PostConstruct
    public void addMyInterceptor() {
        for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
            org.apache.ibatis.session.Configuration conf = sqlSessionFactory.getConfiguration();
            conf.addInterceptor(new AutoGenerateIdInterceptor());
            conf.addInterceptor(new PrintExceptionSqlInterceptor());
            if (printSql) {
                conf.addInterceptor(new PrintSqlInterceptor());
            }
        }
    }
    /**
     * mybatisPlus的分面插件
     * @return 拦截器
     */
    @Bean
    public PaginationInnerInterceptor paginationInnerInterceptor(){
        return new PaginationInnerInterceptor() ;
    }
    /*
    @Value("${mybatis-plus.configuration.print-sql}")
    private boolean printSql;
    @Bean
    public ConfigurationCustomizer mybatisConfigurationCustomizer() {
        return configuration -> {
            configuration.addInterceptor(new AutoGenerateIdInterceptor());
            configuration.addInterceptor(new PrintExceptionSqlInterceptor());
        };
        /*
        return new ConfigurationCustomizer() {
            @Override
            public void customize(MybatisConfiguration configuration) {
                configuration.addInterceptor(new AutoGenerateIdInterceptor());
                configuration.addInterceptor(new PrintExceptionSqlInterceptor());
            if (printSql) {
                configuration.addInterceptor(new PrintSqlInterceptor());
            }
        };
        */
        //return new ConfigurationCustomizer() {
        //    @Override
        //    public void customize(MybatisConfiguration configuration) {
        //        configuration.addInterceptor(new AutoGenerateIdInterceptor());
        //       configuration.addInterceptor(new PrintExceptionSqlInterceptor());
        //    }
        //};
    }
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
@@ -32,5 +75,5 @@
        // 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
        return interceptor;
    }
    */
}
pms-parent/pms-common/src/main/java/com/dy/common/mybatis/PrintSqlHelp.java
New file
@@ -0,0 +1,123 @@
package com.dy.common.mybatis;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.TypeHandlerRegistry;
import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
/**
 * @Author: liurunyu
 * @Date: 2025/5/20 15:31
 * @Description
 */
public class PrintSqlHelp {
    /**
     * 获取完整的执行SQL
     */
    public static String getFullSql(Configuration configuration, BoundSql boundSql) {
        try {
            return parseAndExtractFullSql(configuration, boundSql);
        } catch (Exception e) {
            // 如果解析失败返回原始SQL
            return boundSql.getSql();
        }
    }
    /**
     * 组装完整的sql语句并把对应的参数都代入到sql语句里面
     *
     * @param configuration Configuration
     * @param boundSql      BoundSql
     * @return sql完整语句
     */
    private static String parseAndExtractFullSql(Configuration configuration, BoundSql boundSql) {
        // 获取mapper里面方法上的参数
        Object sqlParameter = boundSql.getParameterObject();
        // sql语句里面需要的参数
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        // sql原始语句(?还没有替换成我们具体的参数)
        String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
        if (!parameterMappings.isEmpty() && sqlParameter != null) {
            // sql语句里面的?替换成真实的参数
            TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
            if (typeHandlerRegistry.hasTypeHandler(sqlParameter.getClass())) {
                sql = sql.replaceFirst("\\?", getParameterValue(sqlParameter));
            } else {
                MetaObject metaObject = configuration.newMetaObject(sqlParameter);
                for (ParameterMapping parameterMapping : parameterMappings) {
                    // 按顺序把?替换成对应的值
                    String propertyName = parameterMapping.getProperty();
                    if (metaObject.hasGetter(propertyName)) {
                        Object obj = metaObject.getValue(propertyName);
                        sql = sql.replaceFirst("\\?", getParameterValue(obj));
                    } else if (boundSql.hasAdditionalParameter(propertyName)) {
                        Object obj = boundSql.getAdditionalParameter(propertyName);
                        sql = sql.replaceFirst("\\?", getParameterValue(obj));
                    }
                }
            }
        }
        return sql;
    }
    /**
     * 获取参数对应的string值
     *
     * @param obj 参数对应的值
     * @return string
     */
    private static String getParameterValue(Object obj) {
        String value;
        if (obj instanceof String) {
            value = "'" + obj + "'";
        } else if (obj instanceof Date) {
            DateFormat formatter =
                    DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);
            value = "'" + formatter.format(obj) + "'";
        } else {
            if (obj != null) {
                value = obj.toString();
            } else {
                value = "";
            }
        }
        // 对特殊字符进行转义,方便之后处理替换
        return value != null ? makeQueryStringAllRegExp(value) : "";
    }
    /**
     * 转义正则特殊字符 ($()*+.[]?\^{}
     * \\需要第一个替换,否则replace方法替换时会有逻辑bug
     */
    private static String makeQueryStringAllRegExp(String str) {
        if (str != null && !"".equals(str)) {
            return str.replace("\\", "\\\\")
                    .replace("*", "\\*")
                    .replace("+", "\\+")
                    .replace("|", "\\|")
                    .replace("{", "\\{")
                    .replace("}", "\\}")
                    .replace("(", "\\(")
                    .replace(")", "\\)")
                    .replace("^", "\\^")
                    .replace("$", "\\$")
                    .replace("[", "\\[")
                    .replace("]", "\\]")
                    .replace("?", "\\?")
                    .replace(",", "\\,")
                    .replace(".", "\\.")
                    .replace("&", "\\&");
        }
        return str;
    }
}
pms-parent/pms-common/src/main/java/com/dy/common/mybatis/PrintSqlInterceptor.java
New file
@@ -0,0 +1,63 @@
package com.dy.common.mybatis;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
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.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
/**
 * @Author: liurunyu
 * @Date: 2025/5/20 15:31
 * @Description
 */
/**
 * 拦截执行SQL执行场景,并将SQL打印出来
 * 拦截Executor里面的query和update方法
 */
@Intercepts({
        @Signature(
                method = "query",
                type = Executor.class,
                args = {
                        MappedStatement.class,
                        Object.class,
                        RowBounds.class,
                        ResultHandler.class
                }
        ),
        @Signature(
                type = Executor.class,
                method = "update",
                args = {
                        MappedStatement.class,
                        Object.class
                }
        )
})
@Slf4j
public class PrintSqlInterceptor  implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        if (args != null && args.length > 1) {
            MappedStatement mappedStatement = (MappedStatement) args[0];
            Object parameter = args[1];
            String sqlId = mappedStatement.getId();
            BoundSql boundSql = mappedStatement.getBoundSql(parameter);
            Configuration configuration = mappedStatement.getConfiguration();
            log.info("\nSQL Id: " + sqlId + "\nSQL Parameters: " + boundSql.getParameterObject() + "\nSQL: " + PrintSqlHelp.getFullSql(configuration, boundSql) + "\n");
        }
        return invocation.proceed();
    }
}