mybatis의 xml mapper는 dynamic sql도 지원하고 있습니다. 저는 처음에 배울 때, if나 foreach 정도만을 써 왔는데요. trim도 알아두면 상당히 강력한 도구가 될 듯 싶습니다. 검색 api를 보면서 감을 잡아보도록 하겠습니다.

 


 저번 시간에 모든 책을 get 하는 api를 작성한 적이 있었습니다. 이것을 Query 파라미터로 받게 바꾸어 보겠습니다. 

 

 

 저는 bookClass와 bookName을 선택적인 Query parameter로 받게끔 하였습니다. 만약에, 해당 Key가 없다면, null 값으로 들어갈 겁니다. 왜냐하면 모델 book의 bookClass는 int가 아닌 Integer로 선언되었기 때문입니다.

 

 

 쿼리 결과는 위와 같이 나와야 합니다.

 

 먼저 BookMapper의 selectAll의 파라미터를 Book으로 바꿉니다.

 

 

 다음에, parameterType을 com.example.library.model.Book으로 바꾸었습니다. 이는 Book 모델 객체를 파라미터로 받기 때문입니다. 여기서 중요한 것은, trim인데요. prefix, prefixOverrides, suffix, suffixOverrides 등이 있어요. 문서에서는 select where 부분과 update set을 예시로 들어가면서 사용 방법을 설명하고 있어요.

 


  먼저, trim prefix는 문서에 따르면 아래와 같은 알고리즘으로 동작합니다.

 

 containing 태그에 content가 존재하면 prefix에 WHERE가 들어오고, 아니면 추가하지 않습니다. trim 밑에 포함되어 있는 태그는 if 태그 2개입니다.

 

 

 따라서, 순서도를 다시 그려보면 이렇게 됩니다. <if>에 1번째 콘텐츠가 존재하기 위해서는 bookClass 필드가 null이 아니여야 합니다. 그리고, 2번째 콘텐츠가 존재하려면 bookName이 null이 아니여야 합니다. 만약에 둘 중 하나라도 있다면 select ~ from ~이 나온 다음에, where가 추가될 겁니다.

 

 다음에 prefixOverrides를 보도록 합시다. 일단 안에 "AND |OR "이 있는데요. "AND "와 "OR "이 파이프로 연결되어 있습니다. 이는, 패턴이 "AND "와 "OR "이라는 의미입니다. 문서를 잘 읽다 보면, "AND "나 "OR "로 콘텐츠가 시작하는 경우에, 이것을 적절히 제거해야 한다는 문구가 있습니다.

 

 그러면서, 다음 단락에 The result is the removal of anything specified in the prefixOverrides attribute. 라는 문구가 또 있어요. 이를 직역하면, prefixOverrides에 나오는 패턴을 제거한다고 해석이 됩니다. 설명만 보면 뭔가 좀 불친절한 거 같습니다. 문서에 나와 있는 예제를 보면 대강 유추할 수 있는데요. prefix에 "AND "나 "OR "이 나오면 제거하게 됩니다. 예를 들어 보면, bookClass가 null이면서, bookName이 null이 아닌 경우를 생각해 봅시다. 35번째 줄에 의하면, AND book_name = ~ 가 trim의 결과물일 겁니다.

 

 

 이 때, prifixOverrides에 의해서, AND 로 시작한다면 이 부분을 제거합니다. 그런데 이렇게 끝나면, select ~ from ~ book_name = ~ 이런 이상한 sql문이 나올 겁니다. 놀랍게도 이 부분은 prefix 속성 때문에 해결할 수 있습니다.

 

 

 이제 select ~ from ~ WHERE book_name = ~ 은 이상한 sql문이 아니므로, 정상적으로 동작하게 됩니다.

 


 마무리 작업이 남았습니다.

 

 

 Mapper 인터페이스의 selectAll이 Book 객체를 받게 되어 있으니, Book 객체를 넘겨줍니다.

 

 

 다음에, Controller의 viewBook은 bookClass와 bookName을 받게 바꿉니다. 이 둘을 받아서 새롭게 Book 객체를 생성한 다음에, BookClass와 BookName을 셋팅하고, bookservice에 넘겨서 처리하게끔 하면 됩니다.