개발 이야기/Spring

[Spring] @ModelAttribute 사용할 때 주의할 점

제이온 (Jayon) 2021. 10. 10.

 

안녕하세요? 제이온입니다.

오늘은 @ModelAttribute에 설명보다는 개발하면서 느낀 주의 사항에 대해 설명드리려고 합니다. 

 

@ModelAttribute 바인딩이 되지 않는 이슈

우테코 다라쓰 팀 프로젝트 도중 @RequestParam 여러 개 쓰기 귀찮아서 @ModelAttribute를 사용하여 Dto를 바인딩하기로 결정했습니다. 저는 이 어노테이션을 파라미터 앞에 쓰면 단순히 여러 개의 파라미터를 하나의 객체로 바인딩해 주는 정도로만 이해하고 있었습니다. 그래서 제가 평소에 만들듯이 요청 Dto를 정의하고, 해당 객체 옆에 @ModelAttribute를 붙여주었습니다.

 

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class CommentReadSecretCommentRequest {

    private Long guestUserId;

    private String guestUserPassword;
}

 

하지만, 위 객체에는 파라미터로 들어온 id와 password가 제대로 바인딩이 되지 않았습니다. 여기서 @NoArgsConstructor을 제거해 주니 정상적으로 바인딩이 되었고, 이유를 찾아 보았습니다.

 

먼저, Spring은 URL 파라미터 또는 POST Form Data 형태의 파라미터를 위와 같은 특정 클래스의 자동으로 바인딩해 주는데, 이때 반환되는 객체를 커맨드 객체라고 부릅니다. 그리고 커맨드 객체를 구성하기 위한 매핑 규칙은 다음과 같습니다.

 

1. NoArgsConstructor과 AllArgsConstructor 둘 다 있는 경우

NoArgsConstructor 호출하고, setter 호출하여 param을 필드에 각각 초기화한다.

 

2. AllArgsConstructor만 있는 경우

AllArgsConstructor 호출하여 param을 필드에 각각 초기화한뒤, setter 호출하여 param을 필드에 각각 다시 초기화하여 덮어 씌운다.

 

즉, 제가 처음에 설계한 객체는 매핑 규칙 1번에 해당하지만 setter가 존재하지 않아서 param들을 필드에 초기화해줄 수 없던 것이었습니다. 그래서 기존에 붙여 두었던 @NoArgsConstructor을 제거하였습니다.

 

번외로, Controller의 파라미터 옆에 @ModelAttribute를 붙이지 않아도 자동으로 커맨드 객체를 구성해 준다고 합니다. 스프링 단에서 int나 String같은 단순한 자료형은 @RequestParam으로 인식하고, 그 외의 복잡한 객체는 @ModelAttribute로 인식한다는데, 그럼에도 스프링은 간단한 숫자나 문자로된 요청도 복잡한 객체로 인식할 여지가 있으므로 어노테이션을 붙여주는 것이 좋다고 생각합니다.

 

정리

평소에 요청 Dto를 Jackson 라이브러리를 통해 역직렬화하는 경우가 많아서 위의 3가지 어노테이션을 주로 사용하여 객체를 구성했었습니다. 이제는 @ModelAttribute에서의 매핑 규칙을 이해하였으므로 요청 Dto를 설계할 때, 사용 목적에 맞게 설계할 수 있을 듯합니다.

댓글

추천 글