--- tags : RequestBody --- @RequestBody === # @RequestBody ```java public class A{ @PostMapping("/opr/cmpgn/requestbody") public String requestbody(@RequestBody @Valid User user, BindingResult result){ log.info("user : " + user); return user.getOutlinkCategoryCode(); } } ``` @RequestBody 는 기본적으로 HTTP Body 를 읽고 컨버팅을 하는데, 헤더의 accept 가 뭔지 에 따라 어떤 컨버터를 쓸지 결정한다. 예를들어 applicaiton/xml 이 전달되면 `Jaxb2RootElementHttpMessageConverter` 를, application/json 이 전달되면 `MappingJackson2HttpMessageConverter` 를 이용해서 컨버팅 한다. (이하 잭슨) accept가 없으면 우선순위로 하나씩 시도해보고 컨버팅 이 성공한 결과를 준다. ### @RequesetBody 는 왜쓰나? 위에서 얘기했지만 json 같은 요청을 처리하기위해 쓴다. key-value 의 단순형식으로는 트리나 배열형을 만들기가 어려울때 쓴다. 특히 불특정 다수의 클라이언트 를 지원하기 위해서는 Json 으로 커뮤니케이션 해야 하는 경우 쓰이게 된다. ### @RequestBody 는 프로퍼티 바인딩 과정이 없다. 내부적으로 Json 파싱을 위해 잭슨을 이용한다고 했다. 잭슨은 `com.fasterxml.jackson.databind.ObjectMapper` 라는 클래스를 이용해서 요청파라미터들을 객체에 write 하는 과정까지 다 해버린다. 즉 바인딩이 해야할 일을 잭슨의 `ObjectMapper` 가 처리 해 버린 셈이다. 바인딩을 안하기 때문에, 바인딩 과정중에 진행되는 컨버전서비스, 커스텀PE 들이 동작하지 않아 개발자가 등록한 모든 컨버터 들이 무용지물이 된다. 즉 @ModelAttribute와 달리 객체생성 과정중 2번이 아래처럼 변경된 것이다. 1. 모델객체 생성 // new User() 2. ~~프로퍼티 바인딩~~ -> ObjectMapper 의 매핑 // setter() 불필요 3. 검증 ### 잭슨은 프로퍼티 바인딩을 안하면 어떤 원리로 필드에 값을 write 하나? 리플렉션으로 한다. setter() 도 필요없다. > 리플렉션은 런타임에 클래스,메소드,필드 구조를 파악할수 있는데, 이걸로 필드의 값을 직접 write 하는 API 라고 이해하면 된다. 하지만 고맙게도 setter() 메소드가 존재 한다면 setter로 주입 해준다. 이런 유연함이 있어, 전처리 하기에도 유용하다. 위에서도 얘기했지만 단점은 컨버전서비스, PE 들을 쓰지 못하는데, 잭슨에서 @JsonFormat, @JsonPropery, @JsonIgnore 등 직렬화/역직렬화 과정을 도와주는 어노테이션들이 많으니 참고하자. 아래의 Yun Blog 가 깔끔한데 참고하도록 하자. > [Jackson 어노테이션 사용법(1/5)](https://cheese10yun.github.io/jackson-annotation/) ~ > [Jackson 어노테이션 사용법(5/5)](https://cheese10yun.github.io/jackson-annotation-05/) 위에것 다 봤으면 아래도 간단하게 훑어보자. > [Spring에서 Json으로의 입출력 정리](https://madnix.tistory.com/entry/Spring%EC%97%90%EC%84%9C-Json%EC%9C%BC%EB%A1%9C%EC%9D%98-%EC%9E%85%EC%B6%9C%EB%A0%A5-%EC%A0%95%EB%A6%AC) ### 결론 @ReqeustMapping 장점 1. setter가 없어도 된다. 2. post 처리를 템플릿 레이어와 분리할수 있다. 3. 웬만한 포매팅은 Jackson이 어노테이션으로 지원 해 준다. @ReqeustMapping 단점 1. 요청 파라미터는 key-value 형식은 쓸수가 없어 json 직렬화 해줘야 한다. 2. 프레젠테이션 레이어가 Jackson 에 의존하게 된다. 3. DataBinder에 등록된 컨버터를 갖다쓸수가 없다. 단점중 3번 때문에 @ModelAttribute 사용시 컨버터 만드는게 꺼려지게 된다. 같이 사용이 안되니까. ## 부록. 프로퍼티 바인딩도 필드접근 방식 설정이 가능하다. 객체 불변성을 위해 setter() 는 반드시 없는게 좋다. @RequestBody 쓸때는 잭슨의 ObejctMapper가 알아서 리플렉션해주는데 @ModelAttribute는 방법이 없을까? 있다. @ModelAttribute를 처리할때 사용되는 프로퍼티 바인딩도 `webDataBinder.initDirectFieldAccess();` 를 설정 해주면 리플렉션으로 접근이 가능하다. Controller 또는 ControllerAdvice 에 적용하면 된다. 설정이 옵셔널 한 이유는, 아마도 리플렉션이 나중에 생겼기 때문에 하위호환을 위한듯 싶다. ### 프로퍼티 바인딩 필드접근 vs Jackson의 ObejctMapper의 필드접근 의 차이점 프로퍼티 바인딩의 initDirectFieldAccess 설정으로 필드접근을 허용 하더라도, 잭슨의 ObjectMapper 의 필드접근과는 차이가 있다. #### initDirectFieldAccess 프로퍼티 바인딩 - setter() 가 있던 없던 필드에 직접 접근해서 바인딩 해준다. #### Jackson의 ObjectMapper 매핑 - setter() 가 있으면 setter를 통해서, 없으면 직접 접근해서 바인딩 해준다. 결론적으로 잭슨의 ObjectMapper 가 더 유연하다. (@RequestBody가 더 유연하다) setter() 를 통해 전처리 후 주입 하기를 원할때가 있는데, 무시하고 필드를 접근 해 버리기 때문이다. 쓰다보니까 깨달은건데, 이럴때 쓰라고 프로퍼티 바인딩에는 컨버터가 있는건가? ObjectMapper는 setter() 에서 전처리가 가능하니까 컨버터가 없는건가? 잘 모르겠다.