
Bean Validation - 수정에 적용상품 수정에도 빈 검증(Bean Validation)을 적용해보자!
edit(): Item 모델 객체에 @Validated를 추가하자.editForm으로 이동하는 코드 추가Bean Validation - 한계데이터를 등록할 때와 수정할 때는 요구사항이 다를 수 있다.

package hello.itemservice.domain.item;
@Data
public class Item {
    @NotNull //수정 요구사항 추가
    private Long id;
    
    @NotBlank
    private String itemName;
    
    @NotNull
    @Range(min = 1000, max = 1000000)
    private Integer price;
    
    @NotNull
    //@Max(9999) //수정 요구사항 추가
    private Integer quantity;
    
    ...
}
수정 요구사항을 적용하기 위해 다음을 적용했다.
id: @NotNull 추가quantity: @Max(9999) 제거Bean Validation - groups동일한 모델 객체를 등록할 때와 수정할 때 각각 다르게 검증하는 방법에 대해 알아보자!
BeanValidation의 groups 기능을 사용한다.Item을 직접 사용하지 않고, ItemSaveForm, ItemUpdateForm 같은BeanValidation - groups 기능 사용이런 문제를 해결하기 위해 Bean Validation은 groups라는 기능을 제공한다.
이 groups 기능을 이용해서 등록 시에 검증할 기능과 수정 시에 검증할 기능을 각각 그룹으로 나누어 적용할 수 있다.
Item - groups 적용@Data
public class Item {
    @NotNull(groups = UpdateCheck.class) //수정시에만 적용
    private Long id;
 
    @NotBlank(groups = {SaveCheck.class, UpdateCheck.class})
    private String itemName;
 
    @NotNull(groups = {SaveCheck.class, UpdateCheck.class})
    @Range(min = 1000, max = 1000000, groups = {SaveCheck.class, UpdateCheck.class})
    private Integer price;
 
    @NotNull(groups = {SaveCheck.class, UpdateCheck.class})
    @Max(value = 9999, groups = SaveCheck.class) //등록시에만 적용
    private Integer quantity;
    
    ...
}

📌
groups기능 정리
groups기능을 사용해서 등록과 수정 시에 각각 다르게 검증할 수 있었다.- 하지만 사실
 groups기능은 잘 사용하지 않는다.
- 사용하기 복잡하고,
 - 실무에서는 등록용 폼 객체와 수정용 폼 객체를 분리해서 사용하기 때문에
 groups를 적용할 일이 없기 때문이다!
Form 전송 객체 분리 - 프로젝트 준비 V4
Form 전송 객체 분리 - 소개실무에서는 groups를 잘 사용하지 않는다.
등록 시 폼에서 전달하는 데이터가 Item 도메인 객체와 딱 맞지 않기 때문이다.
그래서 보통 Item을 직접 전달받는 것이 아니라,
복잡한 폼의 데이터를 컨트롤러까지 전달할 별도의 객체를 만들어서 전달한다.
Item 도메인 객체 사용
HTML Form → Item → Controller → Item → Repository
Item 도메인 객체를 컨트롤러, 리포지토리까지 직접 전달해서 중간에 Item을 만드는 과정이 없어서 간단하다.groups를 사용해야 한다.
HTML Form → ItemSaveForm → Controller → Item 생성 → Repository
Item 도메인 객체를 폼 전달 데이터로 사용하고, 그대로 쭉 넘기면 편리하겠지만,
실무에서는 Item의 데이터만 넘어오는 것이 아니라 무수한 추가 데이터가 넘어온다. 
그리고 더 나아가서 Item을 생성하는데 필요한 추가 데이터를 데이터베이스나 다른 곳에서 찾아와야 할 수도 있다.
따라서 이렇게 폼 데이터 전달을 위한 별도의 객체를 사용하고, 등록, 수정용 폼 객체를 나누면 등록, 수정이
완전히 분리되기 때문에 groups를 적용할 일은 드물다.
Form 전송 객체 분리 - 개발Item 대신 ItemSaveForm을 전달받는다.
@Validated로 검증을 수행하고, BindingResult로 검증 결과를 받는다.
Bean Validation - HTTP 메시지 컨버터@Valid, @Validated는 HttpMessageConverter(@RequestBody)에도 적용할 수 있다.
Postman을 이용해서 테스트📌
API
- 성공 요청: 성공
 - 실패 요청: JSON을 객체로 생성하는 것 자체가 실패함.
 - 검증 오류 요청: JSON을 객체로 생성하는 것은 성공했고, 검증에서 실패함.
 


price 값에 숫자가 아닌 문자를 전달해서 실패하도록 만들자.


HttpMessageConverter에서 요청 JSON을 Item 객체를 생성하지 못한다.
이 경우는, 객체가 생성되지 않았기 때문에 컨트롤러 자체가 호출되지 않고 그 전에 예외가 발생한다.  물론 Validator도 실행되지 않는다. 
이번에는 수량(quantity) 검증 오류가 발생하도록 해보자.


return bindingResult.getAllErrors();는 ObjectError와 FieldError를 반환한다. 
스프링이 이 객체를 JSON으로 변환해서 클라이언트에 전달했다.
@ModelAttirbute vs. @RequestBody
@ModelAttribute는 필드 단위로 정교하게 바인딩이 적용된다.
특정 필드가 바인딩 되지 않아도 나머지 필드는 정상 바인딩 되고,Validator를 사용한 검증도 적용할 수 있다.
@RequestBody는HttpMessageConverter단계에서 JSON 데이터를 객체로 변경하지 못하면 이후 단계 자체가 진행되지 않고 예외가 발생한다.
컨트롤러도 호출되지 않고,Validator도 적용할 수 없다.