北屋教程网

专注编程知识分享,从入门到精通的编程学习平台

MyBatis-Plus SQL日志_mybatisplus日志级别配置

MyBatis-Plus 日志拦截器

EnhancedSqlLogInterceptor -> 拦截日志 SqlLogHandler -> 拓展功能:实现接口自定义处理日志

import com.baomidou.mybatisplus.core.toolkit.SystemClock;
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.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.beans.factor #技术分享y.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Array; import java.sql.Statement; import java.text.SimpleDateFormat; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors;

@Slf4j @Component @Intercepts({ @Signature(type = StatementHandler.class, method = "query", args = {Statement.class, org.apache.ibatis.session.ResultHandler.class}), @Signature(type = StatementHandler.class, method = "update", args = {Statement.class}), @Signature(type = StatementHandler.class, method = "batch", args = {Statement.class}) }) public class EnhancedSqlLogInterceptor implements Interceptor {

private static final long SLOW_SQL_THRESHOLD = 1000;

private static final Set<String> HIDE_PARAMS = new HashSet<>(Arrays.asList( "password", "pwd", "secret", "token", "creditCard", "cvv" ));

private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("(?<!\\)\?(?!\?)");

private static final int MAX_LINE_LENGTH = 120;

@Autowired(required = false) private List<SqlLogHandler> sqlLogHandlers;

@Override public Object intercept(Invocation invocation) throws Throwable {

long startTime = SystemClock.now();

try { return invocation.proceed(); } finally { long endTime = SystemClock.now(); long costTime = endTime - startTime;

if (log.isDebugEnabled() || costTime > SLOW_SQL_THRESHOLD || (sqlLogHandlers != null && !sqlLogHandlers.isEmpty())) { String methodName = invocation.getMethod().getName();

StatementHandler statementHandler = (StatementHandler) invocation.getTarget();

BoundSql boundSql = statementHandler.getBoundSql();

String sqlWithPlaceholders = boundSql.getSql().trim();

String completeSql = getCompleteSql(statementHandler, boundSql, sqlWithPlaceholders); String logMsg = buildLogMessage(methodName, completeSql, costTime);

if(costTime > SLOW_SQL_THRESHOLD){ log.warn(logMsg); }else { if(log.isDebugEnabled()){ log.debug(logMsg); } } if(sqlLogHandlers != null && !sqlLogHandlers.isEmpty()){ for (SqlLogHandler sqlLogHandler : sqlLogHandlers) { sqlLogHandler.handle(methodName, completeSql, costTime); } } } } }

private String getCompleteSql(StatementHandler statementHandler, BoundSql boundSql, String sqlWithPlaceholders) { try { List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings == null || parameterMappings.isEmpty()) { return sqlWithPlaceholders; }

MetaObject metaObject = SystemMetaObject.forObject(statementHandler); MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); Configuration configuration = mappedStatement.getConfiguration();

Object parameterObject = boundSql.getParameterObject(); List<Object> paramValues = getParameterValues(boundSql, configuration, parameterObject);

Matcher matcher = PLACEHOLDER_PATTERN.matcher(sqlWithPlaceholders); StringBuffer sb = new StringBuffer(); int paramIndex = 0; while (matcher.find() && paramIndex < paramValues.size()) { String replacement = formatParameter(paramValues.get(paramIndex++)); matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement)); } matcher.appendTail(sb); return sb.toString();

} catch (Exception e) { log.error("获取完整 SQL 失败,将返回原始 SQL", e); return sqlWithPlaceholders; } }

private List<Object> getParameterValues(BoundSql boundSql, Configuration configuration, Object parameterObject) { List<Object> paramValues = new ArrayList<>(); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();

if (parameterMappings != null) { TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); MetaObject metaObject = parameterObject == null ? null : configuration.newMetaObject(parameterObject);

for (ParameterMapping parameterMapping : parameterMappings) { String propertyName = parameterMapping.getProperty();

if (isSensitiveParam(propertyName)) { paramValues.add("******"); continue; }

if (metaObject != null && typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { paramValues.add(parameterObject); } else if (boundSql.hasAdditionalParameter(propertyName)) { Object value = boundSql.getAdditionalParameter(propertyName); paramValues.add(value); } else if (parameterObject == null) { paramValues.add(null); } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { paramValues.add(parameterObject); } else if (metaObject != null) { Object value = metaObject.getValue(propertyName); paramValues.add(value); } else { paramValues.add(null); } } } return paramValues; }

private String formatParameter(Object param) { if (param == null) { return "NULL"; }

if (param instanceof String) { return "'" + param + "'"; }

if (param instanceof Date) { return "'" + DATE_FORMAT.format((Date) param) + "'"; }

if (param instanceof Number) { return param.toString(); }

if (param instanceof Boolean) { return Boolean.TRUE.equals(param) ? "1" : "0"; }

if (param instanceof byte[]) { return "[BINARY]"; }

if (param instanceof Collection) { return formatCollection((Collection<?>) param); }

if (param.getClass().isArray()) { return formatArray(param); }

return "'" + param.toString() + "'"; }

private String formatCollection(Collection<?> collection) { StringBuilder sb = new StringBuilder(); for (Object item : collection) { if (sb.length() > 0) sb.append(","); sb.append(formatParameter(item)); } return sb.toString(); }

private String formatArray(Object array) { StringBuilder sb = new StringBuilder(); int length = Array.getLength(array); for (int i = 0; i < length; i++) { if (sb.length() > 0) sb.append(","); sb.append(formatParameter(Array.get(array, i))); } return sb.toString(); }

private boolean isSensitiveParam(String paramName) { if (paramName == null) return false;

String lowerParamName = paramName.toLowerCase(); return HIDE_PARAMS.stream() .anyMatch(hideParam -> lowerParamName.contains(hideParam.toLowerCase())); }

private String buildLogMessage(String method, String sql, long costTime) { return String.format("\n" + "┌───────────────────────────────────────────────────────────────────────────────\n" + "│ SQL 方法: %s\n" + "│ 执行时间: %d ms\n" + "│ 完整 SQL: \n" + "%s" + "└───────────────────────────────────────────────────────────────────────────────", method, costTime, formatSqlForDisplay(sql)).replace("│ \n",""); }

private String formatSqlForDisplay(String sql) { List<String> formattedLines = new ArrayList<>(); StringBuilder currentLine = new StringBuilder();

String[] tokens = sql.split("\s+");

for (String token : tokens) { if (currentLine.length() + token.length() + 1 > MAX_LINE_LENGTH) { formattedLines.add(currentLine.toString()); currentLine = new StringBuilder(); }

if (currentLine.length() > 0) { currentLine.append(" "); } currentLine.append(token);

if (isKeyword(token)) { formattedLines.add(currentLine.toString()); currentLine = new StringBuilder(); } }

if (currentLine.length() > 0) { formattedLines.add(currentLine.toString()); }

return formattedLines.stream() .map(line -> "│ " + line) .collect(Collectors.joining("\n")) + "\n"; }

private boolean isKeyword(String token) { if (token == null || token.isEmpty()) { return false; }

String upperToken = token.toUpperCase(); return upperToken.equals("SELECT") || upperToken.equals("FROM") || upperToken.equals("WHERE") || upperToken.equals("JOIN") || upperToken.equals("INNER") || upperToken.equals("LEFT") || upperToken.equals("RIGHT") || upperToken.equals("GROUP") || upperToken.equals("ORDER") || upperToken.equals("HAVING") || upperToken.equals("LIMIT") || upperToken.equals("OFFSET") || upperToken.equals("UNION") || upperToken.equals("VALUES"); }

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

@Override public void setProperties(Properties properties) { } }

SQL SqlLogHandler 接口

public interface SqlLogHandler {

void handle(String methodName, String completeSql, long costTime); }

SQL SqlLogHandler 实现类demo

import org.slf4j.Logger;
import org.springframework.stereotype.Component;

@Component public class DBLogHandler implements SqlLogHandler {

private static final Logger logger = org.slf4j.LoggerFactory.getLogger(DBLogHandler.class);

@Override public void handle(String methodName, String completeSql, long costTime) { logger.info("当前操作用户 :{}", SecurityUtils.getCurrentUserId()); logger.info("DBLogHandler{}: {} costTime: {}", methodName, completeSql, costTime); AsyncExecutor.execute(() -> logger.info("异步执行器 DBLogHandler{}: {} costTime: {}", methodName, completeSql, costTime)); } }
控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言