Bean Validation - SpringBoot

Jiwon Park·2023년 5월 17일
0

의존성 추가

implementation 'org.springframework.boot:spring-boot-starter-validation'

자동으로 Bean Validator를 인지하고 스프링에 통합한다.

자동으로 LocalValidatorFactoryBean 을 글로벌 Validator로 등록한다. 이 Validator는 @NotNull 같은 애노테이션을 보고 검증을 수행한다. 이렇게 글로벌 Validator가 적용되어 있기 때문에 @Valid ,@Validated 만 적용하면 된다.

검증 오류가 발생하면, FieldError , ObjectError 를 생성해서 BindingResult 에 담아준다.


검증 순서

1. @ModelAttribute 각각의 필드에 타입 변환 시도

  • 1) 성공하면 다음으로
  • 2) 실패하면 typeMismatch 로 FieldError 추가

2. Validator 적용


Bean Validation - 에러 코드

BeanValidation 메시지 찾는 순서
1. 생성된 메시지 코드 순서대로 messageSource 에서 메시지 찾기
2. 애노테이션의 message 속성 사용 @NotBlank(message = "공백! {0}")
3. 라이브러리가 제공하는 기본 값 사용

@NotBlank(message = "공백! {0}")
private String itemName;
@NotNull
@Range(min = 1000, max = 1000000)
private Integer price;
@NotNull
@Max(9999)
private Integer quantity;

@NotBlank

  • NotBlank.item.itemName
  • NotBlank.itemName
  • NotBlank.java.lang.String
  • NotBlank

@Range

  • Range.item.price
  • Range.price
  • Range.java.lang.Integer
  • Range

errors.properties

NotBlank=={0}을 입력해주세요.
Range={0}, {2} ~ {1} 까지 가능합니다.
Max=최대 {1}까지 가능합니다.

#==ObjectError==
totalPriceMin.item=상품의 가격 * 수량의 합은 {0}원 이상이어야 합니다. 현재 값 = {1}
totalPriceMin=전체 가격은 {0}원 이상이어야 합니다. 현재 값 = {1}

#==타입 변환 실패시==
typeMismatch.java.lang.Integer=숫자를 입력해주세요!
typeMismatch=타입 오류입니다.

{0} = 필드명


application.properties

spring.messages.basename=messages, errors

 @PostMapping("/add")
    public String addItem(@Validated @ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes) {

        //Object Error
        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/addForm";
        }
        //성공 로직
        Item savedItem = itemRepository.save(item);
        redirectAttributes.addAttribute("itemId", savedItem.getId());
        redirectAttributes.addAttribute("status", true);
        return "redirect:/validation/v3/items/{itemId}";
    }

*참고

@ModelAttribute는 필드 단위로 세밀하게 바인딩이 적용된다. 특정 필드가 바인딩 되지 않아도 나머지 필드는 정상 바인딩 되고, Validator를 사용한 검증도 적용할 수 있다.
@RequestBody는 전체 객체 단위로 적용되기 때문에 HttpMessageConverter 단계에서 JSON 데이터를 객체로 변경하지 못하면 예외가 발생한다. 컨트롤러도 호출되지 않고, Validator도 적용할 수 없다.

profile
안녕하세요

0개의 댓글