221013 TIL @RequestBody vs @ModelAttribute

@ModelAttribute 어노테이션에 대해 알아보던 중 @ModelAttribute도 @RequestBody와 같이 client에서 보낸 데이터를 자바 객체로 변환시켜서 자바에서 사용할 수 있게 만드는 역할을 한다는 것을 알게 되었다.

똑같은 역할을 하는 것 같은데 어느 경우에는 @ModelAttribute를 쓰고 어떤 경우에는 @RequestBody를 사용하는지 궁금해졌다.

그래서 @ModelAttribute와 @RequestBody와의 차이점을 알아봤다.

@ModelAttribute

@ModelAttribute 어노테이션은 client가 보내는 HTTP parameter를 자바 객체에 바인딩하는 역할을 한다.

form형태의 데이터나 url뒤에 붙어서 오는 쿼리 스트링 형태(/user? name=jun&age=25)의 데이터를 처리한다.

 

@RequestBody

@RequestBody는 client가 body에 JSON형태나 XML 방식으로 데이터를 전송하면 이 데이터를 MessageConverter를 이용해 자바 객체로 변환하는 역할을 한다.

 

@ModelAttribute vs @RequestBody

@ModelAttribute와 @RequestBody의 차이는 @ModelAttribute는 HTTP parameter의 데이터를 자바 객체로 바인딩하는 것이고 @RequestBody는 HTTP 요청 본문에 JSON이나 XML을 자바 객체로 변환하는 것이다.

 

정리를 해도 글로만으로는 와닿지 않아 코드로 직접 실험을 해봤다.

 

우선 controller를 하나 만들어서 @RequestBody 어노테이션을 사용할 때와 @ModelAttribute 어노테이션을 사용할 때 각각 동일한 요청 값으로 테스트를 진행해봤다.

 

 

Controller

Controller.test

 

위 코드는 @RequestBody를 이용해서 body에 요청한 name과 age가 자바 객체로 변환이 제대로 되었는지 확인하기 위한 테스트이다.

테스트 결과는 아주 잘 통과하는 것을 볼 수 있다.

 

이제 위 상태에서 컨트롤러의 @RequestBody만 @ModelAttribute로 바꿔서 동일한 테스트를 진행해봤다.

 

Controller

 

테스트 결과는 아쉽게도(?) 실패다.

 

테스트의 내용을 보면 요청에는 body에 전달해준 name:jun과 age:25는 잘 요청이 되었다.

 

Request

 

하지만 응답을 보면 Body에 name과 age의 값이 null이 나오는 것을 볼 수 있다..

 

Response

 

이 테스트 결과로 @ModelAttribute 어노테이션은 요청 body의 값을 자바 객체로 바인딩하지 못하는 것을 알 수 있다.

그러면 위에서 배웠던 @ModelAttribute의 역할에 맞게 값을 parameter로 전달해서 테스트를 진행해봤다.

이전과 똑같은 코드에 테스트 코드에서 param만 추가해줬다.

 

Controller.test

테스트 결과는 여전히 실패했다.

테스트의 내용을 보면 요청에 Parameters로 name과 age가 잘 들어간 것을 볼 수 있다.

 

Request

 

그런데 이전과 같이 응답에서 null이 나오고 있었다.

Response

 

null이 나오는 이유를 찾아보니 @ModelAttribute를 사용해서 파라미터 값을 객체에 바인딩하기 위해서는 객체에 setter가 있어야 한다는 정보를 보고 setter를 생성해서 위 테스트를 다시 진행해봤더니 통과하는 것을 확인할 수 있었다.

 

@ModelAttribute를 사용하면 HTTP 파라미터의 값을 자바 객체에 바인딩한다. 그리고 객체의 필드에 접근해 데이터를 바인딩하기 위해서는 setter 메서드가 필요하다.

 

+ setter메서드가 없어도 해당 객체의 모든 필드를 매개변수로 받는 모든 생성자를 갖고 있으면 setter 없이도 바인딩이 되는 것을 추가로 확인했다.