[문제]
다음과 같이 컨트롤러에서 Ajax가 보낸 request를 받아 응답해주는 코드가 있다.
포스트맨으로 테스트를 먼저 해봤는데 잘 동작하는 것을 확인하였다.
그런데 HTML에 뿌리니까 다음과 같은 에러가 발생하였다.
IDEA 콘솔에는 다음과 같은 에러가 발생하였다.
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public java.lang.Object com.ildong.esg.view.qis.controller.UserQisController.productTableAjax(com.ildong.esg.common.model.PagingDTO$PagingRequest)]
[시도]
- JSON 형식이 다른가 해서 확인해보니 넘겨주는 params의 데이터는 같음을 확인하였다.
- 에러 코드를 보면 url뒤로 쿼리 파라미터 형식으로 데이터가 왔음을 확인하였다. → 그러면 RequestParam으로 받아야 하나?
→ 크롬 콘솔에는 같은 에러가 출력되었다.
→ IDEA 콘솔에는 에러 메시지가 조금 변경되었다.
Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required request parameter 'request' for method parameter type PagingRequest is not present]
→ RequestMapping은 쿼리 스트링으로 데이터가 와야 하는데 ‘?request=’ 형태가 안 왔기 때문이다.
3. 아무것도 붙이지 않기
→ 잉 되네? 왜?
[분석]
데이터를 받는 방식은 크게 2가지로 구분된다.
- JSON 데이터를 요청받을 때 사용하는 @RequestBody
JSON형태로 요청을 받는 경우 Jackson 라이브러리가 객체 안의 필드 이름을 기준으로 매핑해서 파싱 해준다. 따라서 JSON은 객체를 이용해서 요청을 받을 수 있다.
- 쿼리 파라미터를 요청 데이터 받기
다음 에러 코드를 보면 데이터 형식이 쿼리 스트링 형식이므로 @RequestParam을 이용하는 것이 맞다. 따라서 다음과 같이 작성하면 제대로 동작할 것이다.
만약에, 파라미터로 여러 개의 데이터가 온다면 @RequestParam을 개수만큼 적어주어야 하고 이는 코드를 지저분하게 만들 것이다. 이를 해결하기 위해 등장한 것이 @ModelAttribute이다.
@ModelAttribute는 쿼리 파라미터로 넘어온 데이터를 객체 형태로 받을 수 있도록 도와준다. 따라서 다음과 같이 필드 이름을 맞춰서 객체를 만들어 준다면 자동 맵핑이 될 것이다.
@Data
@NoArgsConstructor
public class RequestDto {
int page;
int limit;
String searchType;
}
그렇다면, 메서드의 매개변수에 @ModelAttribute를 붙이지 않았는데 어떻게 동작할 수 있었을까?
→ 기본적으로 @RequestParams와 @ModelAttribute는 생략이 가능하다. 스프링은 기본 타입은 @RequestParams를 자동으로 붙여주며, 객체인 경우 @ModelAttribute를 붙여서 처리한다.
[결론]
- 요청을 받는 방법에는 크게 2가지가 있다. → 쿼리 파라미터와 JSON 데이터
- 쿼리 파라미터를 받는 방법은 @RequestParams 어노테이션을 이용하는 것인데 쿼리 파라미터로 데이터가 여러 개 오는 경우 코드를 지저분하게 만든다.
- 이를 해결하기 위해 등장한 것이 @ModelAttribute이다.
- @ModelAttribute와 @RequestMapping은 생략이 가능한데, 스프링에서 기본 타입은 @RequestParams로 처리하고 객체 타입은 @ModelAttribute로 처리한다.