@ModelAttribute
예제 코드
@Data
@NoArgsConstructor
@ToString
public class HelloData {
private String username;
private int age;
public HelloData(String username, int age) {
this.username = username;
this.age = age;
}
public static HelloData of(String username, int age) {
return new HelloData(username, age);
}
}
@ResponseBody
@GetMapping("/model-attribute-v1")
public ResponseEntity<HelloData> modelAttributeV1(@ModelAttribute HelloData helloData) {
log.info("HelloData = {}", helloData);
return ResponseEntity.ok(helloData);
}
실행 결과
{
"username": "hyun6ik",
"age": 28
}
- 스프링 MVC는 @ModelAttribute가 있으면 다음을 실행한다.
- HelloData 객체를 생성한다.
- 요청 파라미터 이름으로 HelloData 객체의 프로퍼티를 찾는다.
- 그리고 해당 프로퍼티의 setter를 호출해서 파리머터의 값을 입력(바인딩)한다.
- ex) 파라미터 이름이 username이면 setUsername() 메소드를 찾아서 호출하면서 값을 입력한다.
프로퍼티
- 객체에 getUsername(), setUsername() 메소드가 있으면 이 객체는 username이라는 프로퍼티를 가지고 있다.
- username 프로퍼티의 값을 변경하면 setUsername()이 호출되고 조회하면 getUsername()이 호출된다.
바인딩 오류
- age = abc 처럼 숫자가 들어가야 할 곳에 문자를 넣으면 BindException이 발생한다.
@ModelAttribute 생략
@ResponseBody
@GetMapping("/model-attribute-v2")
public ResponseEntity<HelloData> modelAttributeV2(HelloData helloData) {
log.info("HelloData = {}", helloData);
return ResponseEntity.ok(helloData);
}
- @ModelAttribute는 생략할 수 있다.
- 그런데 @RequestParam도 생략할 수 있으니 혼란이 발생할 수 있다.
- 스프링은 해당 생략시 다음과 같은 규칙을 적용한다.
- String, int, Integer 같은 단순 타입 -> @RequestParam
- 나머지 -> @ModelAtrribute(argument resolver로 지정해둔 타입 외)
- argument resolver ex) HttpServletResponse ...