My Life/2025년
[긁어쓰는 소스] Mybatis에서 SQL호출시 세션정보를 공통적으로 추가하는 방법
우라질레이터
2025. 2. 14. 16:03
(1) config.xml
<?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"> <!-- Solme ECM --> <configuration> <settings> <setting name="mapUnderscoreToCamelCase" value="true" /> <setting name="jdbcTypeForNull" value="NULL" /> </settings> <!-- Mybatis Intercept --> <plugins> <plugin interceptor="solme.ecm.system.MybatisInterceptor" /> </plugins> </configuration> |
(2) MybatisInterceptor.java
package xxxx.xxxx.xxxx; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.log4j.Logger; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.binding.MapperMethod.ParamMap; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Plugin; import org.apache.ibatis.plugin.Signature; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.reflection.SystemMetaObject; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.sql.Connection; /** * Mybatis Interceptor * - Mybatis sql호출시 intercept해서 세션정보를 공통으로 추가 * - intercept method는 "prepare"보다는 "update"/"query" 권고 : prepare는 결국 update 또는 query를 호출함 * @author : 황상규 * @date : 2025.02.14 */ @Intercepts({ @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}) //@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class} ) }) public class MybatisInterceptor implements Interceptor { private final static Logger logger = Logger.getLogger(MybatisInterceptor.class); @Override public Object intercept(Invocation invocation) throws Throwable { Object[] args = invocation.getArgs(); if (args != null && args.length > 1) { //-------------------------------------------------------- // (1) 웹 요청이 아닌 경우(ex 배치프로그램) : 웹 요청 정보(HttpServletRequest, HttpSession) 사용 불가 if(RequestContextHolder.getRequestAttributes() == null) { return invocation.proceed(); } //-------------------------------------------------------- // (2) 웹 요청 : 세션에서 값 가져오기 ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); HttpServletRequest request = attr.getRequest(); HttpSession session = request.getSession(false); // 세션이 없으면 null 반환 String ssUserId = null; String ssLanguage = null; if (session != null) { UserInfo userInfo = (UserInfo) session.getAttribute("userInfo"); if (auth != null) { ssUserId = userInfo.getUserId(); ssLanguage = userInfo.getLanguage(); } } // 세션 값 또는 쿠키 값을 공통 파라미터로 추가 ssLanguage = ssLanguage == null? "KO":ssLanguage; //--------------------------------------------------------------- Object parameterObject = null; BoundSql boundSql = null; String queryID = null; String queryString = null; String interceptsMethod = "update_query"; // prepare, update or query switch(interceptsMethod) { //--------------------------------------------------- // (1) method = "prepare" case "prepare" : // MyBatis의 StatementHandler 가져오기 StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); parameterObject = statementHandler.getBoundSql().getParameterObject(); // MyBatis 내부 객체에 접근하기 위해 MetaObject 사용 MetaObject metaObject = SystemMetaObject.forObject(statementHandler); MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); // SQL ID 가져오기 queryID = mappedStatement.getId(); // BoundSql 가져오기 (실제 SQL 쿼리 포함) boundSql = statementHandler.getBoundSql(); queryString = boundSql.getSql(); // 실행될 SQL 문장 // 기존 파라미터 가져오기 parameterObject = boundSql.getParameterObject(); // 파라미터가 null이면 새로운 HashMap 생성 if (parameterObject == null) { parameterObject = new HashMap<String, Object>(); // MyBatis 내부적으로 parameterObject를 대체할 수 있도록 설정 metaObject.setValue("delegate.boundSql.parameterObject", parameterObject); } // 파라미터가 null이면 새로운 HashMap 생성 if (parameterObject instanceof Map) { Map<String, Object> paramMap = (Map<String, Object>) parameterObject; paramMap.put("ssUserId", ssUserId); paramMap.put("ssLanguage", ssLanguage); } else if (parameterObject instanceof Domain) { invokeSetterIfExists(parameterObject, "ssUserId", ssUserId); invokeSetterIfExists(parameterObject, "ssLanguage", ssLanguage); } break; //--------------------------------------------------- // (2) method = "update" or "query" case "update_query" : case "update" : case "query" : default : queryID = ((MappedStatement) invocation.getArgs()[0]).getId(); parameterObject = invocation.getArgs()[1]; if(parameterObject != null) { boundSql = ((MappedStatement) invocation.getArgs()[0]).getBoundSql(parameterObject); queryString = boundSql.getSql(); } // 파라메터 유형별 설정 if (parameterObject instanceof Map) { Map<String, Object> paramMap = (Map<String, Object>) parameterObject; paramMap.put("ssUserId", ssUserId); paramMap.put("ssLanguage", ssLanguage); } else if (parameterObject instanceof Domain) { invokeSetterIfExists(parameterObject, "ssUserId", ssUserId); invokeSetterIfExists(parameterObject, "ssLanguage", ssLanguage); } else if (parameterObject instanceof String) { Map<String, Object> paramMap = new HashMap<>(); paramMap.put("value", parameterObject); paramMap.put("ssUserId", ssUserId); paramMap.put("ssLanguage", ssLanguage); invocation.getArgs()[1] = paramMap; // 복호화등 } else if (parameterObject == null) { Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put("ssUserId", ssUserId); paramMap.put("ssLanguage", ssLanguage); invocation.getArgs()[1] = paramMap; // 새로운 Map을 매개변수로 설정 } parameterObject = invocation.getArgs()[1]; break; } System.out.println("**********************************************"); System.out.println("**********************************************"); System.out.println("***************[START]*******************************"); System.out.println(queryID); if(parameterObject != null) { System.out.println(parameterObject.getClass().getName().toLowerCase() + " : " + parameterObject.getClass()); } System.out.println(parameterObject); System.out.println("**************[END]********************************"); System.out.println("**********************************************"); } return invocation.proceed(); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { } //---------------------------------------- /** * domain(Object) setter invoke * @param domain Object * @param fieldName String * @param value Object * @return * @throws Exception */ private void invokeSetterIfExists(Object domain, String fieldName, Object value) { try { // setter 메서드명 String methodName = "set" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); // 해당 클래스의 모든 메서드 조회 Method[] methods = domain.getClass().getMethods(); for (Method method : methods) { // 메서드 이름이 setter 이름과 일치 if (method.getName().equals(methodName) && method.getParameterCount() == 1) { Class<?> paramType = method.getParameterTypes()[0]; // 첫 번째 파라미터 타입 확인 // value가 해당 타입으로 변환 가능하면 setter 호출 if (value == null || paramType.isAssignableFrom(value.getClass())) { method.invoke(domain, value); } } } } catch (Exception e) { e.printStackTrace(); // 기타 예외 처리 (디버깅 목적) } } } |
(3) 파라메터 유형별 SQL내 변수명
파라메터 Type | 내용(예) | 파라메터 변수명 |
Map | selectMap(Map paramMap); | |
selectString(@Param("userId") String userId); | 설정명 : ex) “userId” | |
selectList(List var1); | list 또는 collection | |
selectString(String var1, String var2); | param1, param2 | |
Domain (Value Object) |
selectDomain(UserInfo userinfo); | |
int update( UserInfo userinfo ); | ||
String | selectString(String userId); | value 또는 param1 |
null | selectNull(); |