노트

Bean Validation

Jakarta Bean Validation

백엔드#spring · 연결된 개념 11개

쉽게 말하면

Bean Validation은 필드마다 '비면 안 됨', '8자 이상' 같은 꼬리표를 붙여 두면 들어온 입력을 알아서 검사해 주는 자바 표준이에요. 놀이기구 앞 키 재기 막대처럼 기준에 안 맞는 값은 입구에서 돌려보내죠.

비유가 깨지는 곳 입구 검사가 전부는 아니에요. 클라이언트 검증은 우회되니 서버에서 다시 검사해요. 다른 앱이나 직접 실행한 SQL도 이 검증을 거치지 않아서 마지막 방어선은 DB 제약이에요.

Bean Validation은 객체 필드에 제약 어노테이션(constraint annotation)을 붙여 입력을 검증하는 자바 표준이다(Jakarta Validation, 구현체는 Hibernate Validator). 스프링은 컨트롤러 파라미터에 @Valid가 붙으면 바인딩 직후 검증을 실행한다.

왜 서버에서 검증하나

클라이언트 검증은 사용자 경험을 위한 것이고, 개발자 도구나 직접 만든 요청으로 얼마든지 우회된다. 신뢰 경계(trust boundary)인 서버에서 다시 검증해야 한다(브라우저 요청과 서버 간 요청). 마지막 방어선은 DB 제약이다(데이터 무결성).

public record SignupRequest(
    @NotBlank @Email String email,
    @NotBlank @Size(min = 8, max = 64) String password,
    @Min(14) int age
) {}
 
@PostMapping("/signup")
public ResponseEntity<Void> signup(@Valid @RequestBody SignupRequest req) { ... }
  • 검증에 실패하면 MethodArgumentNotValidException이 나고 기본 응답은 400이다. 오류 형식은 스프링 전역 예외 처리에서 통일한다
  • 표준 제약: @NotNull, @NotEmpty, @NotBlank, @Size, @Min·@Max, @Email, @Pattern, @Past·@Future 등. Hibernate Validator는 @Length, @Range, @URL 같은 것을 더 준다
  • @NotNull(null만 막음), @NotEmpty(빈 문자열·컬렉션도 막음), @NotBlank(공백만 있는 문자열도 막음)를 구분한다
  • 중첩 객체를 검증하려면 그 필드에도 @Valid를 붙인다

커스텀 제약(custom constraint)

@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = StrongPasswordValidator.class)
public @interface StrongPassword {
    String message() default "비밀번호가 너무 약합니다";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
 
public class StrongPasswordValidator implements ConstraintValidator<StrongPassword, String> {
    public boolean isValid(String v, ConstraintValidatorContext ctx) {
        return v != null && v.matches(".*\\d.*") && v.length() >= 10;
    }
}

주의

JPA(Jakarta Persistence, 옛 이름 Java Persistence API) 엔티티에도 같은 어노테이션을 달면 저장 직전에 한 번 더 검증된다. 요청 DTO(Data Transfer Object)에만 있는 필드(비밀번호 확인 등)가 엔티티 검증과 충돌하면 엔티티 쪽 검증을 끄거나(spring.jpa.properties.jakarta.persistence.validation.mode=none) DTO와 엔티티를 분리한다. 장고 쪽의 같은 역할은 DRF 시리얼라이저의 검증이다. 설정 객체 검증에도 쓴다(스프링 설정 외부화와 프로파일).

출처: Jakarta Validation 3.1 명세: Built-in Constraint definitions · Constraint definition · Spring Framework 문서: Java Bean Validation

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • Lombok

    Lombok은 게터·세터·생성자·toString 같은 반복 코드를 어노테이션으로 대신 생성해 주는 자바 라이브러리다. 컴파일할 때 어노테이션 처리기(annotation processor)가 바이트코드(bytecode)에 메서드를 넣는다. 스프링과는 별개 라이브러리라 따로 추가한다.

  • 시큐리티 필터체인

    Spring Security는 요청이 컨트롤러에 닿기 전에 서블릿 필터(servlet filter) 묶음에서 인증·인가를 처리한다. SecurityFilterChain 빈으로 어떤 경로를 열고 막을지 선언한다.

  • 의존성 주입 (DI)

    객체가 필요한 협력 객체를 직접 new로 만들지 않고, 바깥(스프링 컨테이너)에서 넣어 받는 방식. 무엇을 언제 만들고 어떻게 연결할지의 제어가 내 코드에서 컨테이너로 넘어가므로 제어의 역전(Inversion of Control, IoC)이라고도 부른다.

  • 스프링 부트 자동 설정

    스프링 부트는 스프링 앱을 만들 때 반복되던 설정(의존성 버전 맞추기, 서블릿 컨테이너 연결, 배포)을 관례(convention over configuration)로 대신해 주는 도구다. 클래스패스(classpath)에 무엇이 있는지 보고 필요한 빈을 자동으로 등록하고, 웹 서버를 내장해 java -jar 하나로 실행된다.

  • 인증과 인가

    인증(authentication)은 "너는 누구냐"를 확인하는 것이고, 인가(authorization)는 "너는 이걸 해도 되냐"를 판단하는 것이다. 인증이 먼저고 인가가 그다음이다.

보기 옵션