@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
}
}