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;
//...
}
애노테이션 하나로 검증 로직을 매우 편리하게 적용 가능
스프링 부트는 자동으로 글로벌 Validator로 등록한다.
LocalValidatorFactoryBean
을 글로벌 Validator로 등록한다. 이 Validator는 @NotNull
같은
애노테이션을 보고 검증을 수행한다. 이렇게 글로벌 Validator가 적용되어 있기 때문에, @Valid
,
@Validated
만 적용하면 된다.
검증 오류가 발생하면, FieldError
, ObjectError
를 생성해서 BindingResult
에 담아준다. 직접 글로벌 validator를 등록하면 애노테이션 기반의 빈 검증기가 동작 X
@ModelAttribute
각각의 필드에 타입 변환 시도
-> 성공하면 다음으로
-> 실패하면 typeMismatch 로 FieldError 추가
2. Validator 적용
오류 코드가 애노테이션 이름으로 등록된다. NotBlank 라는 오류 코드를 기반으로 MessageCodesResolver 를 통해 다양한 메시지 코드가 순서대로
생성된다. 그래서 자세하게 적고싶으면 레벨 정의하고 메시지를 정의해주면된다.
ObjectError 처리하는법
item
에 추가
@ScriptAssert(lang = "javascript", script = "_this.price * _this.quantity >= 10000", message = "총합이 10000원 넘게 해주세요")
실제 사용하기에는 좀 어렵다 그래서 그냥 자바코드로 짜는것을 추천한다.
@PostMapping("/{itemId}/edit")
public String edit(@PathVariable Long itemId, @Validated @ModelAttribute Item
item, BindingResult bindingResult) {
//특정 필드 예외가 아닌 전체 예외
if (item.getPrice() != null && item.getQuantity() != null) {
int resultPrice = item.getPrice() * item.getQuantity();
if (resultPrice < 10000) {
bindingResult.reject("totalPriceMin", new Object[]{10000,
resultPrice}, null);
}
}
if (bindingResult.hasErrors()) {
log.info("errors={}", bindingResult);
return "validation/v3/editForm";
}
itemRepository.update(itemId, item);
return "redirect:/validation/v3/items/{itemId}";
}
수정시 검증 요구사항
데이터를 등록할 때와 수정할 때는 요구사항이 다를 수 있다.
@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 에 값도 없고, quantity 수량 제한 최대 값인 9999도 적용되지 않는 문제가 발생한다.
방법 : Item 사용 x, ItemSaveForm 등 별도 모델 객체 사용