Bean Validation이 기본으로 제공하는 오류 메시지를 좀 더 자세히 변경하고 싶으면 어떻게 하면 될까?
Bean Validation을 적용하고 bindingResult 에 등록된 검증 오류 코드를 보면,
오류 코드가 애노테이션 이름으로 등록된다. 마치 typeMismatch 와 유사하다.
NotBlank 라는 오류 코드를 기반으로 MessageCodesResolver 를 통해 다양한 메시지 코드가 순서대로 생성된다.
@NotBlank
- NotBlank.item.itemName
- NotBlank.itemName
- NotBlank.java.lang.String
- NotBlank
@Range
- Range.item.price
- Range.price
- Range.java.lang.Integer
- Range
errors.properties에 메시지를 등록하면 아래의 항목과 같다.
#Bean Validation 추가
NotBlank={0} 공백X
Range={0}, {2} ~ {1} 허용
Max={0}, 최대 {1}
{0} 은 필드명이고, {1} , {2} ...은 각 애노테이션 마다 다르다.
실행
실행해보면 방금 등록한 메시지가 정상 적용되는 것을 확인할 수 있다.
errors.properties 에 메시지를 우선순위가 먼저인 메시지를 추가하면 우선순위가 먼저인 메시지가 출력된다.
#Bean Validation 추가
NotBlank.item.itemName=상품 이름을 적어주세요.
NotBlank={0} 공백X
Range={0}, {2} ~ {1} 허용
Max={0}, 최대 {1}
BeanValidation 메시지 찾는 순서
1. 생성된 메시지 코드 순서대로 messageSource 에서 메시지 찾기
2. 애노테이션의 message 속성 사용 → @NotBlank(message = "공백! {0}")
3. 라이브러리가 제공하는 기본 값 사용 → 공백일 수 없습니다.
애노테이션의 message 사용 예
@NotBlank(message = "공백은 입력할 수 없습니다.")
private String itemName;
Bean Validation - 오브젝트 오류
Bean Validation에서 특정 필드( FieldError )가 아닌 해당 오브젝트 관련 오류( ObjectError )는 어떻게 처리할 수 있을까?
다음과 같이 @ScriptAssert() 를 사용하면 된다.
@Data
@ScriptAssert(lang = "javascript", script = "_this.price * _this.quantity >= 10000")
public class Item {
//...
}
실행해보면 정상 수행되는 것을 확인할 수 있다. 메시지 코드도 다음과 같이 생성된다.
메시지 코드
- ScriptAssert.item
- ScriptAssert
그런데 실제 사용해보면 제약이 많고 복잡하다. 그리고 실무에서는 검증 기능이 해당 객체의 범위를 넘어서는 경우들도 종종 등장하는데, 그런 경우 대응이 어렵다.
따라서 오브젝트 오류(글로벌 오류)의 경우 @ScriptAssert 을 억지로 사용하는 것 보다는
다음과 같이 오브젝트 오류 관련 부분만 직접 자바 코드로 작성하는 것을 권장한다.
ValidationItemControllerV3 - 글로벌 오류 추가
@PostMapping("/add")
public String addItem(@Validated @ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes, Model model) {
// 특정 필드가 아닌 복합 룰 검증
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);
// bindingResult 는 model Attribute에 안담아도 자동으로 view로 넘겨준다
return "validation/v3/addForm";
}
//성공 로직
Item savedItem = itemRepository.save(item);
redirectAttributes.addAttribute("itemId", savedItem.getId());
redirectAttributes.addAttribute("status", true);
return "redirect:/validation/v3/items/{itemId}";
}
@ScriptAssert 부분 제거
'스프링 > 스프링 웹 개발 활용' 카테고리의 다른 글
[Spring] 등록, 수정 시 Bean Validation 중 Conflict가 발생하는 한계와 이를 개선한 groups (1) | 2023.10.11 |
---|---|
[Spring] 수정화면에 Bean Validation 적용 (0) | 2023.10.10 |
[Spring] Bean Validation 스프링 적용 (1) | 2023.10.05 |
[Spring] 검증 로직을 편리하게 하는 BeanValidation으로 검증하기 (0) | 2023.10.05 |
[Spring] 복잡한 검증 로직을 별도로 분리하여 Validator 생성하기 (1) | 2023.10.05 |
댓글