V4

저장용과 수정용 DTO를 각각 만든다.

Item

import lombok.Data;
import org.hibernate.validator.constraints.Range;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

@Data
public class Item {

    private Long id;
    private String itemName;
    private Integer price;
    private Integer quantity;

    public Item() { }

    public Item(String itemName, Integer price, Integer quantity) {
        this.itemName = itemName;
        this.price = price;
        this.quantity = quantity;
    }
}

저장용 객체

수정용 객체

컨트롤러


Bean Validation - HTTP 메시지 컨버터

@Valid, @ValidatedHttpMessageConverter(@RequestBody)에도 적용할 수 있다.

컨트롤러

  • API의 경우 3가지 경우를 생각해야 한다.

    • 성공 요청 (성공)

    • 실패 요청 : JSON을 객체로 생성하는 것 실패 (JSON parser error)

    • 검증 오류 요청 : JSON을 객체로 생성하는 것은 성공했으나 검증에서 실패

실패 요청 : price에 문자를 입력했을 때

검증 오류 요청 : @Max의 범위를 초과했을 때

bindingResult.getAllErrors()objectErrorFieldError를 반환한다. 스프링은 이 객체를 JSON으로 변환해서 클라이언트에게 전달한다. 실제 개발할 때는 이 객체들을 그대로 사용하지 말고 필요한 데이터만 뽑아서 별도의 API 스펙을 정의해야 한다.

@ModelAttribute vs @RequestBody

HTTP 요청 파라미터를 처리하는 @ModelAttribute는 필드 단위로 정교하게 바인딩이 적용되기 때문에 특정 필드가 바인딩 되지 않아도 나머지 필드는 정상 바인딩 되고 Validator를 사용한 검증도 적용할 수 있다.

@RequestBodyHttpMessageConverter 단계에서 JSON 데이터를 객체로 변경하지 못하면 컨트롤러를 호출하지 못하고 예외가 발생하기 때문에 Validator도 적용할 수 없다.


스프링과 Bean Validation

  • 스프링에서는 어노테이션 기반 검증을 위해 @Valid@Validated 어노테이션을 사용할 수 있으며 사용 방식에 있어 약간 차이가 있다.

  • @Validjakarta.validation에 포함되어 있고, @Validatedorg.springframework.validation.annotation에 포함되어 있으며 @Valid를 사용하기 위해서는 spring-boot-starter-validation 의존성이 필요하다.

  • 두 어노테이션 모두 객체 타입에만 사용할 수 있다. 또한 검증할 객체 바로 앞에 위치해야 하며 검증된 결과는 BindingResult에 담긴다.

  • 검증은 바인딩의 가장 마지막 처리 과정이며 기본적으로 바인딩에 성공한 필드는 검증이 이루어진다.

  • 만약 필드의 타입 변환이 실패하면 실패 결과가 FieldError 객체에 담기고 BindingResult에 보관된다.

  • 타입 변환에 실패한 필드는 기본 값이 저장된 상태에서 검증이 이루어지지만 Validator 구현체에 따라 예외가 발생할 수도 있고 기본 검증이 이루어질 수 있다.

클래스 구조

img.png

검증 처리 흐름도

img_1.png

여기서 ConstraintValidator에는 다양한 검증기들이 정의되어 있다.

img_2.png

커스텀 검증 애노테이션 만들기

ConstraintValidator 인터페이스를 구현하여 커스텀 검증 애노테이션을 만들 수 있다.

img_3.png

주어진 제약 조건 A에 대해 검증 대상 타입 T를 검증하는 인터페이스이다.

  • isValid() : 검증 작업을 수행한다. 검증 대상 객체 T는 변경하지 않고 그대로 유지해야 한다.

  • initialize() : 검증기의 isValid() 호출을 준비하기 위해 초기화한다. 검증에 사용되기 전에 먼저 호출 된다.

Last updated