Mybatis로 DB mapper를 수행하는데 interceptor를 등록하면 DB 쿼리 실행 전후로 등록한 interceptor를 수행해서 사전 작업을 할 수 있다.
예를 들어 조회 쿼리 수행시 Paging 처리를 일괄적으로 interceptor에서 할 수 도 있고 Mybatis 쿼리 인자로 세션 정보를 전역에서 설정해서 모든 쿼리마다 해당 세션 값을 넣을 필요 없이 만들 수도 있다.
Mybatis interceptor 설정 방법
mybatis-config.xml 생성
아래와 같이 mybatis-config.xml 설정 파일을 생성한다. 기존에 이미 사용중이라면 plugins 밑에 interceptor class를 등록해준다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true" />
<setting name="callSettersOnNulls" value="true" />
<setting name="jdbcTypeForNull" value="NULL" />
</settings>
<typeAliases>
<typeAlias alias="sql" type="java.util.HashMap"/>
</typeAliases>
<typeHandlers>
<typeHandler javaType="java.lang.String" jdbcType="CLOB" handler="org.apache.ibatis.type.ClobTypeHandler" />
</typeHandlers>
<plugins>
<plugin interceptor="com.sdp.common.interceptor.MybatisExecuteInterceptor"/>
</plugins>
</configuration>
Interceptor Class 정의
Interceptor Class를 만들기 위해서 ibatis 패키지의 Interceptor 인터페이스를 구현하고 @Intercepts, @Signature 어노테이션을 붙여준다.
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.util.Properties;
@Slf4j
@Intercepts({
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class MybatisExecuteInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
@Signature 에는 Mybatis 에서 제공하는 Executor와 Intercept 하고자 하는 메소드 명을 명시 한다. 아래 Interface 들이 라이브러리에서 제공하는 메소드 들이다. 메소드 명에 맞게 SQL수행전에 멈출수도 있고 수행 후 ResultSet을 확인할 수 도 있고 메소드 동작에 따라 Intercept 메소드 전달 인자와 동작 시점이 다르다.
package org.apache.ibatis.executor.resultset;
...
public interface ResultSetHandler {
<E> List<E> handleResultSets(Statement var1) throws SQLException;
<E> Cursor<E> handleCursorResultSets(Statement var1) throws SQLException;
void handleOutputParameters(CallableStatement var1) throws SQLException;
}
package org.apache.ibatis.executor.statement;
...
public interface StatementHandler {
Statement prepare(Connection var1, Integer var2) throws SQLException;
void parameterize(Statement var1) throws SQLException;
void batch(Statement var1) throws SQLException;
int update(Statement var1) throws SQLException;
<E> List<E> query(Statement var1, ResultHandler var2) throws SQLException;
<E> Cursor<E> queryCursor(Statement var1) throws SQLException;
BoundSql getBoundSql();
ParameterHandler getParameterHandler();
}
package org.apache.ibatis.executor;
...
public interface Executor {
ResultHandler NO_RESULT_HANDLER = null;
int update(MappedStatement var1, Object var2) throws SQLException;
<E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, CacheKey var5, BoundSql var6) throws SQLException;
<E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4) throws SQLException;
<E> Cursor<E> queryCursor(MappedStatement var1, Object var2, RowBounds var3) throws SQLException;
List<BatchResult> flushStatements() throws SQLException;
void commit(boolean var1) throws SQLException;
void rollback(boolean var1) throws SQLException;
CacheKey createCacheKey(MappedStatement var1, Object var2, RowBounds var3, BoundSql var4);
boolean isCached(MappedStatement var1, CacheKey var2);
void clearLocalCache();
void deferLoad(MappedStatement var1, MetaObject var2, String var3, CacheKey var4, Class<?> var5);
Transaction getTransaction();
void close(boolean var1);
boolean isClosed();
void setExecutorWrapper(Executor var1);
}
Interceptor Class 생성 시 오버라이드 되는 메소드에서 주의할 것은 아래 와 같이 Proceed 와 Object.wrap을 꼭 선언해주어야 한다. Null을 리턴하면 바로 NullPointException으로 죽어버린다.
public class MybatisExecuteInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 필요한 로직 작성 후
// 아래와 같이 invocation.proceed()로 다음 동작으로 진행시킨다.
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
// 아래와 같이 plugin에 등록한다.
return Plugin.wrap(target, this);
}
물론, 위 mybatis-config.xml을 따로 파일로 작성하였다면 SqlSessionFactory에서 setConfigLocation으로 해당 파일 위치를 등록해주는것을 잊지 말자.
@Configuration
@MapperScan(basePackages = {"com.sdp.common", "com.sdp.mapper"}, sqlSessionFactoryRef="sdpSqlSessionFactory" )
public class SdpDataSourceConfig {
@Value("${spring.mybatis.common.config}")
private String mybatisConfig;
@Value("${spring.mybatis.common.mapper}")
private String mybatisMapper;
@Autowired
ApplicationContext applicationContext;
@Bean(name="dataSource", destroyMethod="close")
@Primary
@ConfigurationProperties(prefix="spring.sdp.datasource")
public DataSource sdpDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name="sdpSqlSessionFactory")
@Primary
public SqlSessionFactory sdpSqlSessionFacotry(@Qualifier("dataSource") DataSource sdpDataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(sdpDataSource);
sqlSessionFactoryBean.setConfigLocation(applicationContext.getResource(mybatisConfig));
sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources(mybatisMapper));
return sqlSessionFactoryBean.getObject();
}
@Bean
@Primary
public SqlSessionTemplate sdpSqlSessionTemplate(SqlSessionFactory sdpSqlSessionFactory) throws Exception {
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sdpSqlSessionFactory);
sqlSessionTemplate.getConfiguration().setMapUnderscoreToCamelCase(true);
return sqlSessionTemplate;
}
}
-- The End --
'Database > Mybatis' 카테고리의 다른 글
[Mybatis] 한번에 여러 쿼리 작성하기 (Oracle PL/SQL BEGIN - END 구문) (0) | 2022.01.09 |
---|