2025년 3월 11일 화요일

sql formmater with mybatis

import org.apache.ibatis.executor.Executor;
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.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import com.github.vertical_blank.sqlformatter.SqlFormatter;

import java.util.List;
import java.util.Properties;

@Intercepts({
    @Signature(
        type = Executor.class,
        method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
    )
})
public class ParameterReplacingInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 쿼리 정보 가져오기
        Object[] args = invocation.getArgs();
        MappedStatement mappedStatement = (MappedStatement) args[0];
        Object parameterObject = args[1];
        BoundSql boundSql = mappedStatement.getBoundSql(parameterObject);

        // 원본 SQL 및 파라미터 처리
        String modifiedSql = replacePlaceholdersWithParameterNames(boundSql);

        // 로그 출력
        System.out.println("Modified SQL:");
        System.out.println(modifiedSql);

        // 실제 실행
        return invocation.proceed();
    }

    private String replacePlaceholdersWithParameterNames(BoundSql boundSql) {
        String sql = boundSql.getSql(); // 원본 SQL
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        Object parameterObject = boundSql.getParameterObject();

        // SQL을 포매팅
        String prettySql = SqlFormatter.format(sql);

        StringBuilder modifiedSql = new StringBuilder(prettySql);
        int questionMarkIndex = 0;

        // `?`를 순차적으로 파라미터 이름으로 치환
        for (ParameterMapping parameterMapping : parameterMappings) {
            String paramName = parameterMapping.getProperty();
            Object value = boundSql.getAdditionalParameter(paramName);

            // AdditionalParameter에서 값을 찾지 못하면 parameterObject에서 가져옴
            if (value == null && parameterObject instanceof Map) {
                Map<?, ?> paramMap = (Map<?, ?>) parameterObject;
                value = paramMap.get(paramName);
            }

            // SQL의 `?`를 `:paramName`로 대체
            questionMarkIndex = modifiedSql.indexOf("?", questionMarkIndex);
            if (questionMarkIndex != -1) {
                modifiedSql.replace(
                    questionMarkIndex,
                    questionMarkIndex + 1,
                    ":" + paramName
                );
                questionMarkIndex += paramName.length() + 1; // 위치 이동
            }
        }

        // 결과 반환
        return modifiedSql.toString();
    }

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

    @Override
    public void setProperties(Properties properties) {
        // 필요 시 설정 추가
    }
}

댓글 없음: