https://sundaland.tistory.com/319
[ ▶ @ModelAttribute ]
@ModelAttribute 어노테이션은 HTTP 요청의 파라미터를 객체에 바인딩하는 데 사용되는 스프링 MVC의 기능이다. 이를 통해 클라이언트가 전송한 폼 데이터나 쿼리 스트링 파라미터를 자동으로 객체에 매핑할 수 있다. 또한, 이 객체는 뷰에서 사용될 모델에 추가될 수 있다. 스프링은 여러 방식으로 @ModelAttribute에 해당하는 객체를 생성하고 바인딩할 수 있으며, 유효성 검사 및 데이터 바인딩 과정에서의 오류 처리도 가능하다.
[ ▷ 기본 개념 ]
@ModelAttribute는 주로 컨트롤러 메서드의 아규먼트로 사용되어, 요청 파라미터를 자동으로 특정 객체에 바인딩한다.
클라이언트가 아래와 같은 HTTP 요청을 통해 데이터를 전송했다고 가정한다.
POST /owners/1/pets/2/edit
Content-Type: application/x-www-form-urlencoded
name=Max&age=5&species=dog
이 요청에서 name, age, species와 같은 파라미터를 Pet 객체로 매핑하고 싶다면, @ModelAttribute를 사용하여 이를 자동으로 처리할 수 있다.
▼ 예시 코드 (Java)
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.stereotype.Controller;
@Controller
public class PetController {
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) {
System.out.println("Pet Name: " + pet.getName());
System.out.println("Pet Age: " + pet.getAge());
System.out.println("Pet Species: " + pet.getSpecies());
return "petDetails";
}
}
- @ModelAttribute Pet pet: Pet 객체에 클라이언트로부터 전달된 요청 파라미터를 바인딩한다. name, age, species 파라미터는 Pet 객체의 필드로 자동으로 매핑된다.
- 메서드 아규먼트로 Pet 객체가 선언되었기 때문에, 스프링은 이를 자동으로 바인딩하고, 그 결과로 생성된 Pet 객체를 메서드 내에서 사용할 수 있다.
[ ▷ 객체 생성 방식 ]
- 기본 생성자: @ModelAttribute로 지정된 객체는 기본적으로 해당 클래스의 기본 생성자를 통해 생성된다.
- 요청 파라미터 매핑: 생성된 객체의 필드에 요청 파라미터가 자동으로 매핑된다. 이 과정에서 스프링은 파라미터 이름과 객체의 필드 이름을 일치시키려고 한다.
- 컨버터 사용: 만약 요청 파라미터가 객체로 변환되기 위해서 특별한 변환이 필요하다면, Converter<String, T>를 구현하여 변환 과정을 추가할 수 있다.
▼ 예시 (경료 변수와의 매핑)
@PutMapping("/accounts/{account}")
public String save(@ModelAttribute("account") Account account) {
//...
}
이 예시에서 account 경로 변수가 Account 객체로 바인딩된다. 스프링은 요청에서 account라는 경로 변수를 찾아, 그것을 Account 객체로 변환한다. 이 과정에서 Converter<String, Account>가 필요할 수 있으며, 이를 통해 데이터베이스에서 Account 객체를 가져오거나 적절한 변환을 수행할 수 있다.
[ ▷ 유효성 검사 및 바인딩 오류 처리 ]
@ModelAttribute는 데이터를 바인딩하는 과정에서 발생하는 오류를 처리할 수 있다. 이를 위해 BindingResult를 아규먼트로 추가할 수 있다. 유효성 검사를 자동으로 적용하고 싶다면 @Valid 또는 @Validated 어노테이션을 추가할 수 있다.
▼ 예시 코드 (유효성 검사 및 오류 처리)
import org.springframework.validation.BindingResult;
import jakarta.validation.Valid;
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// 데이터 처리 로직...
return "petDetails";
}
- @Valid: Pet 객체의 필드에 대해 유효성 검사를 수행한다. 이 검사는 Pet 클래스의 필드에 정의된 제약 조건(예: @NotNull, @Size)을 바탕으로 이루어진다.
- BindingResult: 유효성 검사 결과나 데이터 바인딩 과정에서의 오류를 저장한다. 오류가 있을 경우 이를 처리할 수 있다.
[ ▷ 데이터 바인딩 없이 모델에 값 추가 ]
@ModelAttribute는 데이터 바인딩 없이도 단순히 모델에 객체를 추가할 수 있다. 예를 들어, binding=false 옵션을 사용하면 바인딩을 하지 않고 객체를 모델에 추가할 수 있다.
▼ 예시 코드 (바인딩 없이 모델에 추가)
@ModelAttribute
public AccountForm setUpForm() {
return new AccountForm();
}
@PostMapping("/update")
public String update(@ModelAttribute(binding=false) Account account, AccountForm form) {
// 여기서 Account는 바인딩되지 않음
return "accountDetails";
}
[ ▷ Reactive 스택에서의 사용 (Spring WebFlux) ]
Spring WebFlux에서도 유사하게 @ModelAttribute와 같은 방식으로 요청 파라미터를 객체에 바인딩할 수 있다. 다만, WebFlux는 비동기 처리를 지원하기 때문에 Mono 또는 Flux로 데이터를 처리하게 된다.
▼ Reactive 예시 코드
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.stereotype.Controller;
import reactor.core.publisher.Mono;
@Controller
public class ReactivePetController {
@PostMapping("/reactive-pets/edit")
public Mono<String> processSubmit(@ModelAttribute Pet pet) {
return Mono.just("Processed pet: " + pet.getName());
}
}
- Mono<String>을 통해 비동기 방식으로 결과를 반환한다.
- @ModelAttribute는 Spring WebFlux에서도 기존 MVC 방식과 동일하게 요청 파라미터를 객체에 바인딩한다.
[ ▷ 요약 ]
- @ModelAttribute는 요청 파라미터를 객체에 자동으로 바인딩하는 어노테이션이다.
- 유효성 검사, 오류 처리, 모델에 객체 추가 등의 다양한 기능을 제공한다.
- WebFlux에서도 유사한 방식으로 사용 가능하며, 비동기 처리를 지원한다.
'Web on Servlet Stack' 카테고리의 다른 글
Redirect Attributes (0) | 2024.10.11 |
---|---|
@RequestBody (0) | 2024.10.11 |
Handler Method : @SessionAttribute (0) | 2024.10.11 |
Handler Method : @SessionAttributes (0) | 2024.10.11 |
Annotated Controllers[3] - @CookieValue (0) | 2024.10.11 |