Java/mybatis

Mybatis 실행쿼리 interceptor에 적용하기

바리새인 2025. 1. 29. 00:43
package com.hys.home.interceptor;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.util.List;
import java.util.Map;
import java.util.Properties;

@Slf4j
@Intercepts({
    @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class SqlLogInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // Get the StatementHandler
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();

        // Get the BoundSql
        BoundSql boundSql = statementHandler.getBoundSql();

        // Get the raw SQL and parameters
        String rawSql = boundSql.getSql();
        Object parameterObject = boundSql.getParameterObject();

        // Replace '?' placeholders with actual parameter values
        String finalSql = replacePlaceholdersWithValues(rawSql, boundSql, parameterObject);

        // Log the final SQL
        log.info("Executing SQL:\n{}", finalSql);

        // Proceed with the original method
        return invocation.proceed();
    }

    private String replacePlaceholdersWithValues(String rawSql, BoundSql boundSql, Object parameterObject) {
        // Get the parameter mappings from the BoundSql
        List<org.apache.ibatis.mapping.ParameterMapping> parameterMappings = boundSql.getParameterMappings();

        if (parameterMappings == null || parameterMappings.isEmpty()) {
            return rawSql; // If there are no parameters, return the raw SQL
        }

        // If the parameterObject is a Map, cast it for easier value retrieval
        Map<String, Object> paramMap = (parameterObject instanceof Map) ? (Map<String, Object>) parameterObject : null;

        // Replace '?' placeholders with actual parameter values
        for (org.apache.ibatis.mapping.ParameterMapping parameterMapping : parameterMappings) {
            String propertyName = parameterMapping.getProperty(); // Get the parameter name

            // Get the value from the parameter object
            Object value = (paramMap != null) ? paramMap.get(propertyName) : getValueFromObject(parameterObject, propertyName);

            // Format the value for SQL (e.g., wrap strings in quotes, handle nulls)
            String valueAsString = (value == null) ? "null" : "'" + value.toString() + "'";
            rawSql = rawSql.replaceFirst("\\?", valueAsString.replace("$", "\\$")); // Avoid regex issues with "$"
        }

        return rawSql;
    }

    private Object getValueFromObject(Object parameterObject, String propertyName) {
        try {
            // Use reflection or commons-beanutils to get the value of the property
            return org.apache.commons.beanutils.BeanUtils.getProperty(parameterObject, propertyName);
        } catch (Exception e) {
            // If the property doesn't exist, return null
            return null;
        }
    }

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

    @Override
    public void setProperties(Properties properties) {
        // No additional properties needed
    }
}