검증 작업은 일일이 설정해주는 것은 번거롭기 때문에 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 전송 객체를 분리해서 등록과 수정에 맞는 기능을 구성하고, 검증도 분리할 수 있다.