Bean Validation

wangjh789·2022년 8월 9일
0

[Spring] 스프링-mvc-2

목록 보기
4/11

검증 기능을 매번 코드로 작성하는 방식 대신 애노테이션으로 대체하자

Bean Validation

Bean Validation은 특정한 구현제가 아닌 검증 기술 표준이다.
의존성 추가
implementation 'org.springframework.boot:spring-boot-starter-validation'
validation 의존성을 추가하면 자동으로 Bean Validator를 인지하고 스프링에 통합한다.
스프링부트는 LocalValidatorFactoryBean을 글로번 Validatior로 등록하는데 이것은 어노테이션을 보고 검증을 수행하는 검증기 이다.
검증 오류가 발생하면 FieldError, ObjectError를 만들어 BindingResult에 넣어준다.
(만약 스프링에 글로벌 검증기를 등록한다면 LocalValidatorFactoryBean을 등록하지 않는다.)

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;
    ...
}

검증 순서

  • @ModelAttribute 각각의 필드에 타입 변환 시도
    • 성공하면 다음
    • 실패하면 typeMismatch로 FieldError 추가
  • Validator 적용

-> 바인딩에 성공한 필드만 BeanValidation 적용
(바인딩에 실패한 필드는 BeanValidation을 적용하지 않는다, 의미가 없음)

에러 코드

@NotBlank 의 오류코드를 기반으로 MessageCodesResolver를 통해 메시지 코드가 순서대로 생성된다.
NotBlank.item.itemName
NotBlank.itemName
NotBlank.java.lang.String
NotBlank
따라서 앞서 배운 과정대로 한다면 오류메시지를 재정의 할 수 있다.

ObjectError

@ScriptAssert(lang = "javascript",script = "_this.price*_this.quantity >= 10000")
간단한 경우 위의 애노테이션으로 해결할 수있다.
하지만 제약사항이 너무 많기 때문에 ObjectError 같은 경우 전처럼 자바코드를 사용하는
bindingResult.reject()를 사용하는 것이 더 낫다.

Bean Validation 한계

상품 등록 시의 검증 로직과 수정 시의 검증 로직이 다를 떄는 어떻게 해야할까?
-> Groups 기능을 사용한다.
Groups 기능은 @Validated를 사용해야 한다. 하지만 이 기능이 복잡하고 코드도 길어지기 때문에 실무에선 Groups 대신 각각의 Form객체를 분리시켜 사용한다.

@RequestBody

@RequestBody에도 @Valid를 사용할 수 있다.

  • 성공요청 : 성공
  • 실패요청 : HttpMessageConverter에서 JSON을 객체로 파싱하다가 400에러 발생(컨트롤러까지 들어오지도 않음)
  • 요청성공, 검증로직 실패 : JSON을 객체로 파싱헀지만 BindingResult에 에러가 담겨서 컨트롤러로 들어

@ModelAttribute의 ArgumentResolver는 쿼리파라미터의 필드 하나하나 바인딩을 수행하기 때문에 특정 필드가 실패하더라도 나머지는 정상적으로 잘 담겨서 컨트롤러로 넘겨짐
@RequestBody의 HttpMessageConverter는 JSON 전체를 객체로 반환하기 때문에 특정 필드만 실패해도 바로 400에러를 뱉는다.

profile
기록

0개의 댓글