티스토리 뷰
이번장에서는 Mybatis Interceptor에 대해 알아보자.
말그대로 개발자가 XML 파일에 쿼리를 작성하고 서비스에서 DAO (SQL Mapper)를 호출할때 개발자가 작성한 쿼리를 가로챈다.
Mybatis Interceptor에서는 개발자가 XML 파일에 작성한 SQL의 메타정보들을 얻을 수 있고 파라미터를 가공해서
쿼리를 실행할 수 있다.
예를들어 DB에 고객정보를 저장한다고 가정해보자.
정책에 따라 다르겠지만 고객의 중요한 정보(이름, 연락처, 계좌번호)같은 경우는 평문으로 저장하지않고 복호화 가능한
암호화 데이터로 저장한다. 그럴려면 서비스에서 파라미터 암호화하는 함수를 호출해야하고 조회할때는 복호화하는 함수를호출해줘야 한다.
근데 만일 하나의 애플리케이션에서 암호화해야할 데이터가 고객정보가 아니라 N개가 더 있다고 가정할 때
N개만큼의 암/복호화 함수를 서비스에서 호출해줘야 하는데 이러면 중복된 코드가 계속발생된다.
현재 필자가 진행하고 있는 프로젝트에서 이와같은 일이 있는데 이걸 어떻게 하면 공통으로 뺄 수 있을지 고민하다가
Mybatis Interceptor라는걸 알게되었다.
이걸 적용하면서 2가지 이슈가 발생되었는데 그 이슈와 해결방법까지 알아보자
고객정보 모델객체 및 암/복호화 유틸클래스 생성
AES방식으로 암/복호화하는 유틸클래스를 만들었다. 암/복호화방식이 AES가 아닌 다른방식으로 암호화를 할 수 있기에
별도로 인터페이스를 생성하였고 유틸클래스가 이 인터페이스를 구현한다.
그리고 @CryptoValue라는 어노테이션을 만들었고 이 어노테이션을 선언한 필드에만 암/복호화 적용하도록 하였다.
(AES 암호화방식은 이번장에서 다루지 않겠다)
Mybatis Interceptor 생성
org.apache.ibatis.plugin.Interceptor 인터페이스를 구현하면 intercept 라는 메소드를 오버라이딩 해야한다.
이 메소드의 인자엔 Invocation 객체가 제공되는데 여기엔 파라미터로 전달된 값과 호출된 XML태그에 대한 메타정보들을 얻을 수 있다.
@Signature 어노테이션을 분석해보자
type | Executer라는 인터페이스는 Mybatis의 XML 파일에 작성된 SQL을 실행한다. 해당 인터페이스 내부를 보면 각 mybatis method 시그니처 정보를 볼 수 있다 |
---|---|
method | insert or update or delete가 실행되면 Executer의 update 라는 메소드를 호출하며 select는 query 라는 메소드를 호출한다. |
args | mapper에 작성된 method를 호출할때 전달된 파라미터이다. 공통적으로 MapperStatement라는 객체가 Object[] 타입의 인덱스 0번에 필수로 저장된다. 여기에 XML 메타정보가 담겨있다. |
Mybatis Interceptor 작성
매개변수로 제공된 Invocation 객체로 실행된 메소드이름을 가져올 수 있다. insert, udpate, delete일땐 파라미터를
암호화한 후 쿼리를 실행한다. getArgs() 메서드의 인덱스 1번째요소엔 파라미터로 넘어온 객체가 있으며
proceed() 메소드를 호출하면 SQL이 실행된다.
여기서 반환타입이 Object인데 ArrayList로 casting이 가능하다.
insert, update, delete는 인덱스 0번요소에 적용된 로우의 행의 수만큼 반환되며
select는 resultType에 명시된 ArrayList<resultType에 명시된 타입> 타입으로 반환된다.
SQL 실행전 파라미터 암호화 / select쿼리 결과값 복호화
SQL 실행전에 파라미터는 암호화하고 SQL 실행후 select 쿼리일경우 결과값을 복호화를 한다
주의사항 !!
위에도 말씀드렸다싶이 이걸 구현하면서 2가지 이슈가 발생되었다 했습니다.
첫째는 insert나 update를 할때 간혹 selectKey를 사용해야할 때가 있는데 selectKey를 사용하게되버리면
암호화가 2중으로 되는 이슈가 발생됩니다.
둘째는 select시 count와 list 두개를 조회하는데 첫째처럼 count에서 이미한번 암호화가 되었는데
list조회시 2중으로 되는 이슈가 발생됩니다.
이 둘을 해결하기위해는 Mybatis의 XML 메타정보가 들어있는 MappedStatement의 메소드를 이용하여 쉽게
해결할 수 있습니다.
Mybatis Interceptor 코드변경
XML태그에 작성된 태그 ID를 얻어서 select쿼리중 Count 쿼리만 파라미터 암호화를 한다.
필자가 진행하는 프로젝트 개발환경 규칙에 의하면 count쿼리는 select??Count, list는 select??List이다.
그래서 Count쿼리는 공통적으로 메소드이름 뒤에 Count라는 접미사가 붙게된다.
insert or update에 selectKey가 있으면 태그ID에 !selectKey라는게 접미사로 붙게된다.
그리고 select쿼리중에 selectKey가 아닌 모든 쿼리(list)는 복호화 함수를 호출한다.
이제 설정파일에 추가하고 테스트를 해보자
Mybatis Config에 Interceptor Plugin등록
Mybatis Interceptor 테스트
insert
insert sql을 실행했을때 바로 insert가 되지않고 selectKey가 호출된 이후 insert가 실행되었다.
MybatisInterceptor.java 51 Line에서 파라미터를 암호화 했다. 그리고 60 Line 에서는 암호화 처리를 하지않았다. 여기서 암호화 처리를 했다면 2중으로 암호화 되는 이슈가 되기때문이다.
select
count sql
count sql을 실행했을때 넘어온 파라미터는 평문데이터이다. 그리고 MybatisInterceptor.java 56 Line에 Count sql시 파라미터를 암호화를 하니 실제 바인딩된 값은 암호화된 값이다.
list sql
list sql을 실행했을때는 이미 파라미터가 암호화 되었기 때문에암호화 처리를 하지않았다. 그리고 64 Line에서 list 결과값을 복호화하는 작업을 하였다.
테스트가 정상적으로 완료되었다.
'Mybatis' 카테고리의 다른 글
[Mybatis] - Parameter not found available parameters are 예외는 왜 발생하는 것일까? Mybatis 동작방식 알아보기 (0) | 2021.02.20 |
---|