카테고리 없음2021. 12. 9. 14:40
반응형

@Slf4j
@Intercepts (
{
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
}
)
@Component
public class UpdateInterceptor implements Interceptor {

ObjectMapper paramObjectMapper;

// spring 에서 파라미터 객체 json 출력을 위해 ObjectMapper 생성
@PostConstruct
public void init() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    // 날짜 관련 serializer 추가
    builder.serializerByType(LocalDate.class, new com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer(DateTimeFormatter.ofPattern(DateConstans.DATE)));
    builder.serializerByType(LocalDateTime.class, new com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DateConstans.DATE_TIME)));
    // empty bean fail 처리 disable
    builder.featuresToDisable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
    // 파라미터 객체의 jsonIgnore 된 필드도 출력하기 위한 처리
    builder.annotationIntrospector(new JacksonAnnotationIntrospector() {
         @Override
         protected boolean _isIgnorable(Annotated a) {
                return false;
         }
    });
    paramObjectMapper = builder.build();
}

@Override
public Object intercept(Invocation invocation) throws Throwable {
    Object[] args = invocation.getArgs(); 
    MappedStatement ms = (MappedStatement)args[0];
    Object param = (Object)args[1]; 
    BoundSql boundSql = ms.getBoundSql(param); 

    log.debug("파라미터 바인딩 SQL : {}", getParameterBindingSQL(boundSql, param));
    log.debug("파라미터 JSON : {}" , getParam(param));


    return invocation.proceed();
}


// 파라미터 sql 바인딩 처리
public String getParameterBindingSQL(BoundSql boundSql, Object parameterObject) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, JsonProcessingException {

    StringBuilder sqlStringBuilder = new StringBuilder(boundSql.getSql());

    // stringBuilder 파라미터 replace 처리
    BiConsumer<StringBuilder, Object> sqlObjectReplace = (sqlSb, value) -> {

        int questionIdx = sqlSb.indexOf("?");

        if(questionIdx == -1) {
            return;
        }

        if(value == null) {
            sqlSb.replace(questionIdx, questionIdx + 1, "null");
        } else if (value instanceof String) {
            sqlSb.replace(questionIdx, questionIdx + 1, "'" + (value != null ? value.toString() : "") + "'");
        } else if(value instanceof Integer || value instanceof Long || value instanceof Float || value instanceof Double) {    
            sqlSb.replace(questionIdx, questionIdx + 1, value.toString());
        } else if(value instanceof LocalDate || value instanceof LocalDateTime) {
            sqlSb.replace(questionIdx, questionIdx + 1, "'" + (value != null ? value.toString() : "") + "'");
        } else if(value instanceof Enum<?>) {
            sqlSb.replace(questionIdx, questionIdx + 1, "'" + (value != null ? value.toString() : "") + "'");
        } else {
            sqlSb.replace(questionIdx, questionIdx + 1, value.toString());
        }
    };

    if(parameterObject == null) {
        sqlObjectReplace.accept(sqlStringBuilder, null);
    } else {

        if(parameterObject instanceof Integer || parameterObject instanceof Long || parameterObject instanceof Float || parameterObject instanceof Double || parameterObject instanceof String) {
            sqlObjectReplace.accept(sqlStringBuilder, parameterObject);
        } else if(parameterObject instanceof Map) {

            Map paramterObjectMap = (Map)parameterObject;
            List<ParameterMapping> paramMappings = boundSql.getParameterMappings();

            for (ParameterMapping parameterMapping : paramMappings) {
                String propertyKey = parameterMapping.getProperty();

                try {
                    Object paramValue = null;
                    if(boundSql.hasAdditionalParameter(propertyKey)) { 
                        // 동적 SQL로 인해 __frch_item_0 같은 파라미터가 생성되어 적재됨, additionalParameter로 획득
                        paramValue = boundSql.getAdditionalParameter(propertyKey);
                    } else {
                        paramValue = paramterObjectMap.get(propertyKey);    
                    }

                    sqlObjectReplace.accept(sqlStringBuilder, paramValue);    
                } catch (Exception e) {
                    sqlObjectReplace.accept(sqlStringBuilder, "[cannot binding : " + propertyKey+ "]");
                }

            }
        } else {

            List<ParameterMapping> paramMappings = boundSql.getParameterMappings();
            Class< ? extends Object> paramClass = parameterObject.getClass();

            for (ParameterMapping parameterMapping : paramMappings) {
                String propertyKey = parameterMapping.getProperty();

                try {

                    Object paramValue = null;
                    if(boundSql.hasAdditionalParameter(propertyKey)) {
                        // 동적 SQL로 인해 __frch_item_0 같은 파라미터가 생성되어 적재됨, additionalParameter로 획득
                        paramValue = boundSql.getAdditionalParameter(propertyKey);
                    } else {
                        Field field = ReflectionUtils.findField(paramClass, propertyKey);
                        field.setAccessible(true);
                        paramValue = field.get(parameterObject);    
                    }

                    sqlObjectReplace.accept(sqlStringBuilder, paramValue);
                } catch (Exception e) {
                    sqlObjectReplace.accept(sqlStringBuilder, "[cannot binding : " + propertyKey+ "]");
                }
            }
        }
    }

    return sqlStringBuilder.toString();
}


private String getParam(final Object parameter) throws Exception {
    return paramObjectMapper.writeValueAsString(parameter);
}

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

@Override
public void setProperties(Properties properties) {
    // TODO Auto-generated method stub

}

}

Posted by 1010