1.目录
2.代码
package com.sunxiansheng.mybatis.plus.inteceptor;import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.*;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.vertical_blank.sqlformatter.SqlFormatter;
import com.github.vertical_blank.sqlformatter.languages.Dialect;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;import java.sql.Statement;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
@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 SqlBeautyInterceptor implements Interceptor {private static final Logger logger = LoggerFactory.getLogger(SqlBeautyInterceptor.class);private static final String ANSI_RESET = "\u001B[0m";private static final String ANSI_BRIGHT_GREEN = "\u001B[92m"; private static final String ANSI_BRIGHT_BLUE = "\u001B[94m"; private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler statementHandler = (StatementHandler) invocation.getTarget();MetaObject metaObject = SystemMetaObject.forObject(statementHandler);while (metaObject.hasGetter("h")) {Object object = metaObject.getValue("h");metaObject = SystemMetaObject.forObject(object);}while (metaObject.hasGetter("target")) {Object object = metaObject.getValue("target");metaObject = SystemMetaObject.forObject(object);}MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");Configuration configuration = mappedStatement.getConfiguration();long startTime = System.currentTimeMillis();Object result = null;try {result = invocation.proceed();return result;} finally {long endTime = System.currentTimeMillis();long sqlCost = endTime - startTime;SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();String formattedSql = formatSql(configuration, boundSql);String formattedResult = formatResult(result, sqlCommandType);logger.info("\n========================\n{}SQL 类型:{} {}{}{}\n{}SQL:{}\n{}{}{}\n{}执行耗时:{} {}{}ms{} \n{}结果:{}\n{}{}\n{}========================{}",ANSI_BRIGHT_BLUE, ANSI_RESET,ANSI_BRIGHT_GREEN, sqlCommandType, ANSI_RESET,ANSI_BRIGHT_BLUE, ANSI_RESET,ANSI_BRIGHT_GREEN, formattedSql, ANSI_RESET,ANSI_BRIGHT_BLUE, ANSI_RESET,ANSI_BRIGHT_GREEN, sqlCost, ANSI_RESET,ANSI_BRIGHT_BLUE, ANSI_RESET,ANSI_BRIGHT_GREEN, formattedResult, ANSI_RESET,ANSI_BRIGHT_BLUE, ANSI_RESET);}}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {}private String formatSql(Configuration configuration, BoundSql boundSql) {try {String sql = boundSql.getSql();Object parameterObject = boundSql.getParameterObject();List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();if (parameterMappings != null && !parameterMappings.isEmpty() && parameterObject != null) {TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();MetaObject metaObject = configuration.newMetaObject(parameterObject);for (ParameterMapping parameterMapping : parameterMappings) {String propertyName = parameterMapping.getProperty();Object value;if (boundSql.hasAdditionalParameter(propertyName)) {value = boundSql.getAdditionalParameter(propertyName);} else if (metaObject.hasGetter(propertyName)) {value = metaObject.getValue(propertyName);} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {value = parameterObject;} else {value = null;}sql = replaceFirstQuestionMark(sql, getParameterValue(value));}}return SqlFormatter.of(Dialect.MySql).format(sql);} catch (Exception e) {logger.error("Error formatting SQL: ", e);return boundSql.getSql();}}private String replaceFirstQuestionMark(String sql, String value) {return sql.replaceFirst("\\?", Matcher.quoteReplacement(value));}private String getParameterValue(Object obj) {if (obj == null) {return "null";}if (obj instanceof String) {return "'" + obj + "'";}if (obj instanceof Number) {return obj.toString();}if (obj instanceof java.util.Date || obj instanceof java.sql.Date || obj instanceof java.sql.Timestamp) {return "'" + obj.toString() + "'";}return "'" + obj.toString() + "'";}private String formatResult(Object result, SqlCommandType sqlCommandType) {if (result == null) {return "null";}try {String formattedResult;if (sqlCommandType == SqlCommandType.SELECT) {formattedResult = GSON.toJson(result);} else if (sqlCommandType == SqlCommandType.UPDATE || sqlCommandType == SqlCommandType.DELETE || sqlCommandType == SqlCommandType.INSERT) {formattedResult = result.toString() + " 行受影响";} else {formattedResult = result.toString();}int maxLength = 2000;if (formattedResult.length() > maxLength) {formattedResult = formattedResult.substring(0, maxLength) + "... [结果过长,已截断]";}return formattedResult;} catch (Exception e) {logger.error("Error formatting result: ", e);return result.toString();}}
}