RequestBody 바인딩
서론
이전에 작성한 글 중에 @Requestbody Annotation 사용 시 기본 생성자 필요 라는
글을 올린 적이 있는데 글의 마지막에 보면
@Requestbody가 jackson 라이브러리를 이용해 매핑하기 때문이다.
라는 결론으로 글을 마무리 하였는데, 김영한님의 강의에서 해당 내용과 관련해서 자세하게 알려주시는 부분이 있어, 해당 내용을 정리해본다.
본론
우선 Spring에서는 Controller에서 @RequestBody로 넘어오는 파라미터들에 대해서 내부적으로 ObjectMapper를 이용해 JSON 데이터를 우리가 만든 DTO 객체로 변환시켜주고,
@ResponseBody인 경우엔, DTO 객체를 JSON 데이터로 변환해서 클라이언트에 넘겨준다.
이렇게해서 해소 될 궁금증이었으면 이 글을 읽으러 오지 않았을테니, 해당 내용에 대하여 코드 레벨에서 자세히 알아보기로 한다.
우선, Spring MVC의 동작 순서를 간략하게 서술하자면(구글에 검색하면 훌륭한 분들이 작성하신 훌륭한 글들이 많으므로)
- 클라이언트에서 요청이 넘어오면 FrontController 역할을 수행하는 DispatcherServlet에서 먼저 확인해서,
- 핸들러 매핑 리스트 중 해당 요청을 처리 할 수 있는 핸들러를 가져오고,
- 핸들러 어댑터 리스트 중에서 해당 핸들러를 처리 할 수 있는 핸들러 어댑터를 가져와서,
- 해당 어댑터에서 우리가 만든 컨트롤러에 호출해서 비즈니스 로직을 처리 한 후,
- 리턴되는 데이터에 맞게 뷰 리졸버나 메시지컨버터가 동작하고,
- 알맞게 클라이언트로 반환된다.
여기서, @RequestMapping에 대한 request는 RequestMappingHandlerAdapter에서 처리하는데
이 RequestMappingHandlerAdapter는
1. byte[]를 처리하기 위한 ByteArrayHttpMessageConverter
2. String을 처리하기 위한 StringHttpMessageConverter
3. json을 처리하기 위한 MappingJackson2HttpMessageConverter
등을 가지고 있다.
RequestMappingHandlerAdapter에 설정된 MessageConverter들
그리고 자신이 가지고 있는 ArgumentResolver들 중
@RequestBody형식으로 들어오는 파라미터를 처리하기 위해 RequestResponseBodyMethodProcessor 라는 ArgumentResolver를 호출한다.
RequestMappingHandlerAdapter에 설정된 ArgumentResolver들
이 RequestResponseBodyMethodProcessor의 readWithMessageConverters 메서드에서 메시지 컨버터 리스트를 loop 돌면서
대상 클래스 타입과 미디어 타입 등을 체크해서 알맞은 메시지 컨버터를 호출해서 사용하는데
이 때 호출되는 MessageConverter가 MappingJackson2HttpMessageConverter라는 MessageConverter이다.
요청을 처리 할 수 있는 MessageConverter 호출
- MessageConverter의 canRead() 메서드로 해당 요청을 처리 할 수 있는 컨버터 인지 확인.
- 처리 할 수 있으면 read() 메서드로 메시지에서 객체를 읽고 반환한다.
MappingJackson2HttpMessageConverter에서는 최종적으로 readJavaType 메서드가 호출되는데 이 때 objectMapper를 사용해서 json 데이터를 DTO 객체로 변환하는 것을 볼 수 있다.
ObjectMapper를 이용해서 JSON데이터를 변환하는 부분
결론
보이지 않는 곳에서 이렇게 많은 부분을 스프링에서 처리해주고 있었기 때문에 우리는 Controller에서 편하게 파라미터를 사용 할 수 있고, JSON 데이터도 바로 객체로 받을 수 있는 것이었다.
이런 내용을 알아도, 몰라도 결국 같은 방식으로 개발 하겠지만… 언젠가 도움이 되겠거니 생각하고 지금은 궁금증을 해결 했다는 것에 대해 만족한다.
이 글을 읽는 다른 분들도 필자와 같은 궁금증이 있었다면 조금이나마 해소가 됐길 바라며..