@Data
public class Item {
private Long id;
@NotBlank
private String itemName;
@NotNull
@Range(min = 1000, max = 1000000)
private Integer price;
@NotNull
@Max(9999)
private Integer quantity;
public Item() {
}
public Item(String itemName, Integer price, Integer quantity) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
}
@ModelAttribute
각각의 필드에 타입 변환 시도typeMismatch
로 FieldError
추가수정시에는 Item 에서 id 값이 필수이고, quantity 도 무제한으로 적용할 수 있다.
결과적으로
item
은 등록과 수정에서 검증 조건의 충돌이 발생하고, 등록과 수정은 같은 BeanValidation
을 적용할 수 없다. 이 문제를 어떻게 해결할 수 있을까?
ValidationItemV4Controller
groups
를 잘 사용하지 않는데, 그 이유가 다른 곳에 있다. 바로 등록시 폼에서 전달하는 데이터가 Item
도메인 객체와 딱 맞지 않기 때문이다. Item
도메인 객체가 딱 맞는다. 하지만 실무에서는 회원 등록시 회원과 관련된 데이터만 전달받는 것이 아니라, 약관 정보도 추가로 받는 등 Item
과 관계없는 수 많은 부가 데이터가 넘어온다. 그래서 보통 Item
을 직접 전달받는 것이 아니라, 복잡한 폼의 데이터를 컨트롤러까지 전달할 별도의 객체를 만들어서 전달한다. ItemSaveForm
이라는 폼을 전달받는 전용 객체를 만들어서 @ModelAttribute
로 사용한다. 이것을 통해 컨트롤러에서 폼 데이터를 전달 받고, 이후 컨트롤러에서 필요한 데이터를 사용해서 Item
을 생성한다.@Data
public class ItemSaveForm {
@NotBlank
private String itemName;
@NotNull
@Range(min = 1000, max = 1000000)
private Integer price;
@NotNull
@Max(value = 9999)
private Integer quantity;
}
@Data
public class ItemUpdateForm {
@NotNull
private Long id;
@NotBlank
private String itemName;
@NotNull
@Range(min = 1000, max = 1000000)
private Integer price;
//수정에서는 수량은 자유롭게 변경할 수 있다.
private Integer quantity;
}
@PostMapping("/{itemId}/edit")
public String edit(@PathVariable Long itemId, @Validated @ModelAttribute("item") ItemUpdateForm form, BindingResult bindingResult) {
//...
}
@Valid
, @Validated
는 HttpMessageConverter
( @RequestBody
)에도 적용할 수 있다.참고
@ModelAttribute
는 HTTP 요청 파라미터(URL 쿼리 스트링, POST Form)를 다룰 때 사용한다.
@RequestBody
는 HTTP Body의 데이터를 객체로 변환할 때 사용한다. 주로 API JSON 요청을 다룰 때
사용한다.
HTTP 요청 파리미터를 처리하는 @ModelAttribute
는 각각의 필드 단위로 세밀하게 적용된다. 그래서
특정 필드에 타입이 맞지 않는 오류가 발생해도 나머지 필드는 정상 처리할 수 있었다.
HttpMessageConverter
는 @ModelAttribute
와 다르게 각각의 필드 단위로 적용되는 것이 아니라,
전체 객체 단위로 적용된다.
따라서 메시지 컨버터의 작동이 성공해서 ItemSaveForm
객체를 만들어야 @Valid
, @Validated
가
적용된다.
@ModelAttribute
는 필드 단위로 정교하게 바인딩이 적용된다. 특정 필드가 바인딩 되지 않아도 나머지@RequestBody
는 HttpMessageConverter 단계에서 JSON 데이터를 객체로 변경하지 못하면 이후참고
HttpMessageConverter
단계에서 실패하면 예외가 발생한다. 예외 발생시 원하는 모양으로 예외를
처리하는 방법은 예외 처리 부분에서 다룬다.