MVC2 - Bean Validation

2022. 9. 27. 17:53·Spring

Bean Validation 정의

검증 애노테이션과 여러 인터페이스의 모음 - 인터페이스만 제공하고 구현체를 갈아끼울 수 있음 주로 Hibernate 이용

Hibernate : 객체 관계 매핑 프레임워크

애노테이션만 붙이면 될까? NO! 👉 Validator를 필요로 함

 

Bean Validation 사전준비

build.gradle 의존성 추가

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

jarcarta.validation.api 설치 확인가능 -> hibernate.validator가 실제 구현체로 동작

  • javax.validation (ex:@NotNull, @NotBlank) : 특정 구현에 상관없이 제공하는 표준 인터페이스
  • org.hibernate.validator (ex:@Range) : hibernate 구현체를 사용할 때만 제공되는 검증 기능✨(대부분 이걸 사용)

 

위와 같이 의존성을 추가하면 Spring boot는 자동으로 Validator를 글로벌로 등록해준다.

어노테이션은 @Validated, @Valid  둘 다 사용가능하나, valid 는 위에서 했던 것(build.gradle에서의 starter-validation)과 같이 의존성을 추가해주어야 한다.

 

검증 순서

1️⃣ ModelAttribute의 각 필드에 대해 매핑 시도
2️⃣ 성공시 Validator 적용
3️⃣ 실패 시 typeMismatch로 FieldError 추가

✍ BeanValidator는 바인딩이 실패한 경우 적용하지 않는다. 👉 타입 변환이 성공될 시에만 검증

 

타입 변환 성공 플로우

가격 필드에 숫자 입력 -> 타입 변환 성공 -> Bean Validation 적용 가능

 

타입 변환 오류 플로우

가격 필드에 숫자가 아닌 문자 입력 -> 타입 변환 실패 -> typeMismatch FieldError 추가 -> BeanValidation 적용 불가

 

Bean Validation 기본 에러 메시지 수정 방법

BindingResult에 등록된 검증 오류 코드를 뜯어보게 되면

오류 코드가 애노테이션 이름으로 등록되는 것을 확인 할 수 있다. (마치 typemismatch처럼!)

NotBlank 오류의 경우 MessageResolver 우선순위 순서

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

Bean Validation의 메시지 찾는 순서

1️⃣ Message 코드 순으로 messageSource 에서 메시지 찾기
2️⃣ Annotation에 명시된 message 사용
3️⃣ 라이브러리 제공 기본 값 사용

 

오브젝트 오류

필드 에러가 아닌 오브젝트 에러는 여러 필드의 조합을 필요로한다.

@ScriptAssert를 사용

@ScriptAssert(lang = "javascript", script = "_this.price * _this.quantity >= 10000")

두 개의 필드값의 수식이 참이기를 원하는 어노테이션을 활용한다

해당 오류 메시지는

ScriptAssert.item(오브젝트 이름)
ScriptAssert

와 같은 우선순위로 실행된다.

그러나 위와 같은 방법은 1️⃣객체의 범위를 넘어서는 경우 대응이 어려우며 2️⃣제약이 많고 복잡하기에 따로 자바 코드로 구현하는 것을 권장한다.

필드 에러는 Bean Validation을 사용하고, 오브젝트 에러는 자바 코드를 사용하는 것이 보편적이다.

 

Bean Validation의 한계점

타입 검증의 차별성이 필요할 때 (ex: 데이터를 등록할 때와 수정할 때의 제약사항이 달라지는 경우)

수정 시에는 id값이 필수고, quantity는 무제한이다

id에 @NotNull을 붙여주게 되면, 당연히 등록할 시에는 튕겨버리게 된다😢

하나의 필드에 대한 다른 요구사항이 충돌하게 된다.

이를 해결하기 위해서

1️⃣ Bean Validation Group

2️⃣ ModelAttribute 객체를 분리 - 폼 객체 따로 생성

 

Bean Validation의 한계 극복 방법

Bean Validation Group

등록일 때 이 조건, 수정할 때 이 조건을 사용할 수 있도록 Group을 이용하자

인터페이스 생성

public interface UpdateCheck {
}

NotNull에 group 적용

@NotNull(groups = {UpdateCheck.class})
private Long id;

* Groups 기능을 사용하려면 Validated를 사용해야 한다.

 

ModelAttribute 객체 분리✨ 주로 이용

직접 도메인에 적용하지 않고, 폼 전송을 위한 객체를 분리하자! 별도의 ModelAttribute를 생성하는 것이다.

원하는 특정 정보 뿐만 아니라 부가적인 정보를 받게 되는 경우도 허다하기 때문에 폼을 하나 더 생성해서 ModelAttribute 에 사용한다.

별도의 객체를 생성하게 되면 [👎중간에 실제 객체를 만드는 과정이 추가적으로 필요해지게 되나], [👍검증 로직이 중복되지는 않는다].

Form의 네이밍은 답이 정해져 있지는 않지만 일관성 있게 작성하자! Form, Dto etc.. (나는 프로젝트를 진행할 때 Form을 사용했다 🙃)

앞서 Bean Validation을 주석 처리하고, Save와 Update의 Form 을 분리해서 생성해 주자.

@Data
public class ItemSaveForm {

    @NotBlank
    private String itemName;
@Data
public class ItemUpdateForm {

    @NotNull
    private Long id;

위와 같이 새로 객체를 저장하는 Save의 경우에는 id가 필요 없지만, Update의 경우에는 id가 필수인 경우처럼 검증을 분리할 수 있게 된다.

Controller 수정

ModelAttribute 수정, 객체 변환

@PostMapping("/add")
public String addItemV3(@Validated @ModelAttribute("item") ItemSaveForm form, BindingResult bindingResult, RedirectAttributes redirectAttributes) {
	...
	Item item = new Item();
    item.setItemName(form.getItemName());
    item.setQuantity(form.getQuantity());
    item.setPrice(form.getPrice());
    // 검증 성공
    Item savedItem = itemRepository.save(item);
    ...
}

 

Bean Validation HTTP 메시지 컨버터에 적용(@ReqeustBody)

RequestBody로 숫자 필드에 문자를 대입한 뒤 실행하게 되면, JSON을 객체로 변환할 때 오류가 발생하게 된다. ParsingError 생성(컨트롤러 자체가 호출되지 않음)

API의 세 가지 플로우

1️⃣ 성공

2️⃣ JSON -> 객체 변환 실패

3️⃣ JSON -> 객체 변환 성공 & 검증 실패 👉 예외 처리 필요

 

ModelAttribute, RequestBody 의 검증 차이

  @ModelAttribute @RequestBody
적용 단위 각각의 필드 단위로 정교하게 적용 전체 객체로 정교하게 적용
특정 필드 바인딩이 실패시 나머지 필드에 대해 Validator 적용 가능 다음 단계 진행 불가, 컨트롤러 진입X

 

저작자표시 비영리 변경금지 (새창열림)

'Spring' 카테고리의 다른 글

MVC2 - Filter, Interceptor  (1) 2022.10.05
MVC2 - 로그인(쿠키, 세션)  (1) 2022.10.03
MVC2 - Validation  (0) 2022.09.27
File->MultipartFile  (0) 2022.07.26
QueryDSL 사용 전 환경설정  (0) 2022.07.12
'Spring' 카테고리의 다른 글
  • MVC2 - Filter, Interceptor
  • MVC2 - 로그인(쿠키, 세션)
  • MVC2 - Validation
  • File->MultipartFile
코드파고
코드파고
  • 코드파고
    Digging Code
    코드파고
  • 전체
    오늘
    어제
    • 분류 전체보기 (99)
      • Memorization (12)
      • Spring (18)
      • Java (1)
      • Algorithm (40)
      • Server (2)
      • DB (0)
      • CS (0)
      • CI & CD (4)
      • Architecture (0)
      • Design Patterns (0)
      • Study (1)
      • Book (9)
        • DEV (7)
        • Non-DEV (0)
      • Infra (1)
        • Kafka (6)
        • AWS (4)
      • TroubleShooting (1)
        • Etc (1)
      • Tools (0)
  • 블로그 메뉴

    • 홈
    • Github
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    SpringFramework
    clean architecture
    Spring Boot
    architecture
    Spring독학
    Clean Code
    헥사고날아키텍쳐
    클린아키텍쳐
    알고리즘
    Spring
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
코드파고
MVC2 - Bean Validation
상단으로

티스토리툴바