오봉이와 함께하는 개발 블로그
스프링 MVC 2 - BeanValidation 한계, groups 본문
Bean Validation - 한계
수정시 검증 요구사항
등록시 기존 요구사항
- 타입 검증
- 가격, 수량에 문자가 들어가면 검증 오류 처리
- 필드 검증
- 상품명 : 필수, 공백 X
- 가격 : 1000원 이상, 1백만원 이하
- 수량 : 최대 9999
- 특정 필드의 범위를 넘어서는 검증
- 가격 * 수량의 합은 10,000원 이상
수정시 요구사항
- 등록시에는 quantity 수량을 최대 9999까지 등록할 수 있지만 수정시에는 수량을 무제한으로 변경할 수 있다.
- 등록시에는
id
에 값이 없어도 되지만, 수정시에는 id 값이 필수이다.
수정 요구사항 적용
수정시에는 Item
에서 id
값이 필수이고, quantity
도 무제한으로 적용할 수 있다.
@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;
public Item() {
}
public Item(String itemName, Integer price, Integer quantity) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
}
id
: @NotNull
추가quantity
: @Max(9999)
제거
참고
현재 구조에서는 수정시 item
의 id
값은 항상 들어있도록 로직이 구성되어 있다.
그래서 검증하지 않아도 된다고 생각할 수 있지만, HTTP 요청은 언제든지 악의적으로 변경해서 요청할 수 있기 때문에 서버에서 항상 검증해야 한다.
예를 들어 HTTP 요청을 변경해서 item
의 id
값을 삭제하고 요청할 수도 있다. 따라서 최종 검증은 서버에서 진행하는 것이 안전하다.
수정을 실행하면 정상 동작하는 것을 확인할 수 있다.
하지만 등록에서 문제가 발생한다.
등록시에는 id에 값도 없고, quantity 수량 제한 최대 값인 9999도 적용되지 않는 문제가 발생한다.
등록시 화면이 넘어가지 않으면서 다음과 같은 오류를 볼 수 있다.'id': rejected value [null];
왜냐하면 등록시에는 id
에 값이 없기 때문에 @NotNull id
를 적용한 것 때문에 검증에 실패하고 다시 폼 화면으로 넘어온다.
결국 등록 자체도 불가능하고, 수량 제한도 걸지 못한다.
결과적으로 item
은 등록과 수정에서 검증 조건의 충돌이 발생하고, 등록과 수정은 같은 BeanValidation
을 적용할 수 없다. 이 문제를 어떻게 해결할 수 있을까?
Bean Validation - groups
동일한 모델 객체를 등록할 때와 수정할 때 각각 다르게 검증하는 방법을 알아보자.
두 개의 방법이 있다.
- BeanValidation의 groups 기능을 사용한다.
- Item을 직접 사용하지 않고 ItemSaveForm, ItemUpdateForm 같은 폼 전송을 위한 별도의 모델 객체를 만들어서 사용한다.
BeanValidation groups 기능 사용
BeanValidation은 groups라는 기능을 제공한다.
예를 들어, 등록시에 검증할 기능과 수정시에 검증할 기능을 각각 그룹으로 나누어 적용할 수 있다.
groups 적용
저장용 groups 생성
public interface SaveCheck {
}
수정용 groups 생성
public interface UpdateCheck {
}
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;
public Item() {
}
public Item(String itemName, Integer price, Integer quantity) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
}
ValidationItemControllerV3 - SaveCheck, UpdateCheck Groups 적용
public String addItemV2(@Validated(SaveCheck.class) @ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes, Model model) {
//...
}
public String editV2(@PathVariable Long itemId, @Validated(UpdateCheck.class) @ModelAttribute Item item, BindingResult bindingResult) {
// ...
}
@Valid
에는 groups를 적용할 수 있는 기능이 없다. 따라서 groups를 사용하려면 @Validated
를 사용해야 한다.
- addItem()를 복사해서 addItemV2()생성, SaveCheck.class 적용
- edit()를 복사해서 editV2()생성, UpdateCheck.class 적용
실행하면 정상적으로 작동하는 것을 확인할 수 있다.
정리
groups 기능을 사용해서 등록과 수정시에 각각 다르게 검증을 할 수 있지만 groups 기능을 사용하니 Item은 물론이고, 전반적으로 복잡도가 올라간다.
사실 groups 기능은 실제 잘 사용되지는 않는다. 그 이유는 실무에서는 주로 등록용 폼 객체와 수정용 폼 객체를 분리해서 사용하기 때문이다.
출처 : 인프런 김영한 지식공유자님 강의 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
'BE > Spring' 카테고리의 다른 글
스프링 MVC 2 - BeanValidation HTTP 메시지 컨버터 (0) | 2022.08.28 |
---|---|
스프링 MVC 2 - Form 전송 객체 분리 소개와 개발 (0) | 2022.08.25 |
스프링 MVC 2 - Bean Validation 에러 코드, 오브젝트 오류 (0) | 2022.08.24 |
스프링 MVC 2 - Bean Validator 스프링 적용 (0) | 2022.08.24 |
스프링 MVC 2 - Bean Validation 소개, 시작 (0) | 2022.08.24 |