검증 작업은 일일이 설정해주는 것은 번거롭기 때문에 Bean Validation을 통해 효율적으로 검증할 수 있다.
바로 검증하려는 객체 위에 @애노테이션을 활용하여 검증 조건을 설정해주는 것이다.
@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;
}
@NotBlank : 빈값 + 공백만 있는 경우를 허용하지 않는다.
@NotNull : null 을 허용하지 않는다.
@Range(min = 1000, max = 1000000) : 범위 안의 값이어야 한다.
@Max(9999) : 최대 9999까지만 허용한다.
검증은 Controller에 @ModelAttribute로 객체가 넘어올 때 수행해준다.
@PostMapping("/add")
public String addItem(@Validated @ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes, Model model)
@ModelAttribute 앞에 @Validated를 추가해주면 Item 객체에서 설정해준 Bean Validation을 적용한다.
이는 스프링 부트가 자동으로 글로벌 Validator 를 등록하기 때문에 @NotNull과 같은 애노테이션을 보고 검증해준다.
따라서 개발자는 Controller에 넘어오는 @ModelAttribute 앞에 @Valid, 혹은 @Validated만 추가해주면 된다.
@ModelAttribute 각각의 필드에 타입 변환 시도
즉 바인딩에 성공한 필드만이 우리가 설정한 검증 조건인 BeanValidation을 적용한다.
(바인딩 되지도 않은 필드는 이미 오류가 발생한 필드이므로 세부 조건을 검사할 필요가 없는 것)
Bean Validation을 통해 검증 조건을 설정했지만 Item 이라는 모델은 등록할 때와 수정할 때 다르게 쓰일 수도 있다.
이 때 검증 조건을 다르게 하고 싶지만 Item 모델은 하나이므로 충돌이 발생하게 된다. 이를 해결하기 위해 전송 객체를 분리해야한다.
Item을 처음 등록할 때 사용하는 객체는 ItemSaveForm, Item을 수정할 때 사용하는 객체는 ItemUpdateForm 으로 DTO를 만들어주자.
@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;
}
form에서 전달한 데이터를 ItemSaveForm, ItemUpdateForm 으로 받고 Repository에 저장할 때는 다시 Item Entity에 변환하여 저장해줘야 한다.
Form 전송 객체를 분리해서 등록과 수정에 맞는 기능을 구성하고, 검증도 분리할 수 있다.