Bean Validation(빈검증) 보충자료

Bean Validation을 활용한 검증 및 에러 처리


Bean Validation 기술 개요

Hibernate Validator

  • Bean Validation(표준 사양)을 구현한 가장 널리 사용되는 기술입니다.

  • javax.validation 패키지를 기반으로 다양한 어노테이션(@NotBlank, @Min, @Max 등)을 제공합니다.

글로벌 Validator 빈 등록

  • Spring에서 LocalValidatorFactoryBean을 글로벌 Validator로 등록하여 사용합니다.

  • 이를 통해 Bean Validation을 모든 컨트롤러와 서비스에 적용할 수 있습니다.

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public Validator getValidator() {
        return new LocalValidatorFactoryBean();
    }
}

@Validated 어노테이션

  • @Validated는 Spring에서 Bean Validation을 활성화하기 위해 반드시 사용해야 합니다.

  • 적용 위치:

    • @Controller 메서드 파라미터

    • 서비스 계층 메서드

    • 기타 Bean Validation이 필요한 곳


타입 검증 및 설정 관련

  1. 타입 미스매치 처리

    • Bean Validation은 데이터 바인딩 및 타입 변환 자체를 처리하지 않습니다.

    • 타입 변환 오류는 Spring MVC에서 처리되며, 이를 사용자 정의 메시지로 출력할 수 있습니다.

    • 예시: typeMismatch.user.userId

  2. 메시지 코드 우선순위

    • 검증 메시지의 우선순위는 다음과 같습니다:

      1. NotBlank.user.userName (필드와 객체명 포함)

      2. NotBlank (일반 오류 코드)

  3. 메시지 처리 예시

    NotBlank.user.userName=User Name is required.
    NotBlank=This field is required.
    typeMismatch.user.userId=Invalid format for User ID.

Groups를 활용한 등록/수정 검증 분리

Groups 설정

  • 등록과 수정 시 검증 로직을 다르게 적용해야 하는 경우, Bean Validation의 groups를 사용할 수 있습니다.

Groups 예시

UserGroups.java

public class UserGroups {
    public interface Create {}
    public interface Update {}
}

User.java

import javax.validation.constraints.NotBlank;

public class User {
    
    @NotBlank(groups = UserGroups.Create.class, message = "User ID is required for creation.")
    private String userId;

    @NotBlank(groups = {UserGroups.Create.class, UserGroups.Update.class}, message = "User Name is required.")
    private String userName;

    // Other fields...
}

컨트롤러

@PostMapping("/create")
public String createUser(
    @Validated(UserGroups.Create.class) @RequestBody User user,
    BindingResult bindingResult
) {
    if (bindingResult.hasErrors()) {
        return "errorPage";
    }
    return "successPage";
}

@PutMapping("/update")
public String updateUser(
    @Validated(UserGroups.Update.class) @RequestBody User user,
    BindingResult bindingResult
) {
    if (bindingResult.hasErrors()) {
        return "errorPage";
    }
    return "successPage";
}

@RequestBody@ModelAttribute의 검증 차이

@ModelAttribute

  • 객체 단위로 바인딩되며, 특정 필드에서 타입 오류가 발생해도 나머지 필드는 정상적으로 처리됩니다.

  • 예: userId 타입 오류 발생 시, userName은 정상적으로 바인딩됩니다.

@RequestBody

  • 전체 객체 단위로 처리됩니다.

  • 메시지 컨버터(Message Converter)가 성공적으로 작동해야 Bean Validation이 수행됩니다.

  • 메시지 컨버터 단계에서 오류가 발생하면 Bean Validation은 적용되지 않습니다.


에러 처리 흐름

웹 애플리케이션의 에러 처리 구조

  1. 요청 흐름

    • WAS → 필터 → 서블릿 → 인터셉터 → 컨트롤러 → 예외 발생

  2. 컨트롤러에서 예외 발생 시 처리

    • 예외가 컨트롤러에서 발생하면 아래 흐름에 따라 처리됩니다:

      1. HandlerExceptionResolver: Spring MVC가 제공하는 기본 예외 처리기.

      2. @ExceptionHandler: 컨트롤러 또는 전역에서 커스텀 예외 처리 가능.

      3. Default Error Page: 서블릿 컨테이너에 의해 처리.


Validator 빈 등록 방식 비교

기존 Validator

Bean Validation (Hibernate Validator)

직접 검증 코드 작성

어노테이션 기반의 검증 제공

Errors.rejectValue 사용

@NotBlank, @Min, @Max 등 사용

로직이 복잡하고 반복적인 코드 필요

코드의 간결성과 유지보수 용이

커스텀 Validator 빈 등록 필요

글로벌 Validator (LocalValidatorFactoryBean) 기본 제공


예시 코드

Bean Validation 기반 검증

User.java

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

public class User {

    @NotBlank(message = "User ID cannot be blank.")
    @Size(min = 5, message = "User ID must be at least 5 characters long.")
    private String userId;

    @NotBlank(message = "User Name cannot be blank.")
    private String userName;

    // Other fields...
}

UserController.java

@PostMapping("/create")
public String createUser(
    @Validated @RequestBody User user,
    BindingResult bindingResult
) {
    if (bindingResult.hasErrors()) {
        return "errorPage";
    }
    return "successPage";
}

Last updated