Controller에서 사용되는 @ModelAttribute에 대해서 알아보겠습니다.

@ModelAttribute는 클라이언트가 전달하는 값을 객체로 맵핑해주는 역할을 합니다. HTTP Body 데이터 혹은 HTTP 파라미터를 주입합니다. 이때 생성자나 Setter로 주입하기 때문에 Setter혹은 생성자가 있어야 합니다. 

@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ModelAttribute {

   @AliasFor("name")
   String value() default "";

   @AliasFor("value")
   String name() default "";

   boolean binding() default true;
}

@ModelAttribute name, value 속성

name과 value는 Alias입니다. 둘 중 하나를 골라서 사용합니다. value가 default니 value를 생략하고 이름을 줄 수 있습니다. Html에서 사용하는 이름을 맵핑해줘야 합니다. 

현재 Html을 눌렀을 때 Post로 객체 이름을 Test로 서버에게 보냅니다. 

<form role="form" action="/members/new" th:object="${Test}"
          method="post">
        <div class="form-group">
            <label th:for="name">크기</label>
            <input type="text" th:field="*{name}" class="form-control"
                   placeholder="크기를 입력하세요"
        </div>
        <div class="form-group">
            <label th:for="zipcode">설명</label>
            <input type="text" th:field="*{zipcode}" class="form-control"
                   placeholder="설명를 입력하세요">
        </div>
        <button type="submit" class="btn btn-primary">Submit</button>
    </form>

@ModelAttribute를 HTTP Body Data를 받는 형태로 사용하기 위해서는 Html에서 사용되는 변수명을 입력해줘야 합니니다. 

@GetMapping("/model")
public String modelAttribute(@ModelAttribute("Test") Test test) {
    return test.getSize()+" "+test.getDescription();
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Test{
    int size;
    String description;
}
Model에 데이터를 넘기기 위해서는 model.addAttribute를 이용하여 데이터를 담아서 보내야 하지만  @ModelAttribute를 사용할 경우 model.addAttribute를 사용하지 않아도 데이터가 넘어갑니다. 

@ModelAttribute를 HTTP 파라미터 형태로 사용할 경우 변수명만 일치시키면 됩니다. 

@GetMapping("/model")
public String modelAttribute(@ModelAttribute Test test) { // "/model?size=10&description=hi
    return test.getSize()+" "+test.getDescription(); // 10 hi 반환
}

// ModelAttribute가 아닌 RequestParam으로 받았을 때
@GetMapping("/requestParam")
public String requestParam(@ReqestParam("size") int size, @RequestParam("description") String description){
	return size + " " + description;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Test{
    int size;
    String description;
}

HTTP 파라미터를 이용할 때는 @RequestParam을 이용해서 받을 수 있지만 값들이 많아질 경우 @ModelAttribute를 이용해서 받으면 깔끔해집니다. 

@ModelAttribute binding 속성

binding 속성은 default가 true입니다. 이것은 넘어온 값을 맵핑할지 안 할지 정하는 역할을 합니다.

@GetMapping("/model")
public String modelAttribute(@ModelAttribute(binding = false) Test test) { // "/model?size=10&description=hi
    return test.getSize()+" "+test.getDescription(); // 0 null 반환 binding = false이므로 맵핑x
}

@GetMapping("/model")
public String modelAttribute(@ModelAttribute Test test) { // "/model?size=10&description=hi
    return test.getSize()+" "+test.getDescription(); // 10 hi 반환
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Test{
    int size;
    String description;
}

binding = false를 주면 binding을 하지 않기 때문에 0과 null이 반환됩니다.

지금까지 @ModelAttribute에 대해서 알아봤습니다. 감사합니다.