|
| 1 | +package top.cadecode.framework.handler; |
| 2 | + |
| 3 | +import lombok.extern.slf4j.Slf4j; |
| 4 | +import org.apache.ibatis.executor.Executor; |
| 5 | +import org.apache.ibatis.mapping.BoundSql; |
| 6 | +import org.apache.ibatis.mapping.MappedStatement; |
| 7 | +import org.apache.ibatis.mapping.ParameterMapping; |
| 8 | +import org.apache.ibatis.plugin.Interceptor; |
| 9 | +import org.apache.ibatis.plugin.Intercepts; |
| 10 | +import org.apache.ibatis.plugin.Invocation; |
| 11 | +import org.apache.ibatis.plugin.Signature; |
| 12 | +import org.apache.ibatis.reflection.MetaObject; |
| 13 | +import org.apache.ibatis.session.Configuration; |
| 14 | +import org.apache.ibatis.session.ResultHandler; |
| 15 | +import org.apache.ibatis.session.RowBounds; |
| 16 | +import org.apache.ibatis.type.TypeHandlerRegistry; |
| 17 | +import org.springframework.stereotype.Component; |
| 18 | + |
| 19 | +import java.text.SimpleDateFormat; |
| 20 | +import java.util.Date; |
| 21 | +import java.util.List; |
| 22 | + |
| 23 | +@Slf4j |
| 24 | +@Component |
| 25 | +@Intercepts({ |
| 26 | + @Signature(type = Executor.class, method = "update", |
| 27 | + args = {MappedStatement.class, Object.class}), |
| 28 | + @Signature(type = Executor.class, method = "query", |
| 29 | + args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})}) |
| 30 | +public class MybatisSqlPrintingHandler implements Interceptor { |
| 31 | + |
| 32 | + @Override |
| 33 | + public Object intercept(Invocation invocation) throws Throwable { |
| 34 | + // 获取 SQL 描述语句对象 |
| 35 | + MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; |
| 36 | + // 获取参数 |
| 37 | + Object parameter = null; |
| 38 | + if (invocation.getArgs().length > 1) { |
| 39 | + parameter = invocation.getArgs()[1]; |
| 40 | + } |
| 41 | + // 获取 SQL Id |
| 42 | + String sqlId = mappedStatement.getId(); |
| 43 | + // 获取 BoundSql 即 mybatis 封装的 SQL 对象 |
| 44 | + BoundSql boundSql = mappedStatement.getBoundSql(parameter); |
| 45 | + // 获取配置 |
| 46 | + Configuration configuration = mappedStatement.getConfiguration(); |
| 47 | + // 计时,执行 |
| 48 | + long start = System.currentTimeMillis(); |
| 49 | + Object returnValue = invocation.proceed(); |
| 50 | + long time = System.currentTimeMillis() - start; |
| 51 | + // 打印 SQL |
| 52 | + showSql(configuration, boundSql, time, sqlId); |
| 53 | + return returnValue; |
| 54 | + } |
| 55 | + |
| 56 | + /** |
| 57 | + * 处理 sql 中的字符 |
| 58 | + * |
| 59 | + * @param configuration 配置对象 |
| 60 | + * @param boundSql boundSql |
| 61 | + * @param time 用时 |
| 62 | + * @param sqlId sql id |
| 63 | + */ |
| 64 | + private static void showSql(Configuration configuration, BoundSql boundSql, long time, String sqlId) { |
| 65 | + Object parameterObject = boundSql.getParameterObject(); |
| 66 | + List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); |
| 67 | + // 替换空格、换行、tab缩进等 |
| 68 | + String sql = boundSql.getSql().replaceAll("[\\s]+", " "); |
| 69 | + if (parameterMappings.size() > 0 && parameterObject != null) { |
| 70 | + TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); |
| 71 | + if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { |
| 72 | + sql = sql.replaceFirst("\\?", getParameterValue(parameterObject)); |
| 73 | + } else { |
| 74 | + MetaObject metaObject = configuration.newMetaObject(parameterObject); |
| 75 | + for (ParameterMapping parameterMapping : parameterMappings) { |
| 76 | + String propertyName = parameterMapping.getProperty(); |
| 77 | + if (metaObject.hasGetter(propertyName)) { |
| 78 | + Object obj = metaObject.getValue(propertyName); |
| 79 | + sql = sql.replaceFirst("\\?", getParameterValue(obj)); |
| 80 | + } else if (boundSql.hasAdditionalParameter(propertyName)) { |
| 81 | + Object obj = boundSql.getAdditionalParameter(propertyName); |
| 82 | + sql = sql.replaceFirst("\\?", getParameterValue(obj)); |
| 83 | + } |
| 84 | + } |
| 85 | + } |
| 86 | + } |
| 87 | + logs(time, sql, sqlId); |
| 88 | + } |
| 89 | + |
| 90 | + /** |
| 91 | + * 对不同类型参数进行处理 |
| 92 | + * |
| 93 | + * @param obj 参数 |
| 94 | + * @return 处理后的参数 |
| 95 | + */ |
| 96 | + private static String getParameterValue(Object obj) { |
| 97 | + String value; |
| 98 | + if (obj instanceof String) { |
| 99 | + value = "'" + obj + "'"; |
| 100 | + } else if (obj instanceof Date) { |
| 101 | + // 处理日期类型 |
| 102 | + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| 103 | + value = "'" + sdf.format(new Date()) + "'"; |
| 104 | + } else { |
| 105 | + value = obj != null ? obj.toString() : ""; |
| 106 | + } |
| 107 | + return value.replace("$", "\\$"); |
| 108 | + } |
| 109 | + |
| 110 | + /** |
| 111 | + * 打印 log |
| 112 | + * |
| 113 | + * @param time 用时 |
| 114 | + * @param sql sql 语句 |
| 115 | + * @param sqlId sql id |
| 116 | + */ |
| 117 | + private static void logs(long time, String sql, String sqlId) { |
| 118 | + log.info("sql 日志 => 执行 [" + sqlId + "] 用时 " + time + " 毫秒"); |
| 119 | + log.info("sql 日志 <= 语句:" + sql); |
| 120 | + } |
| 121 | +} |
0 commit comments