Updated:

1. 개요

일반적으로 데이터 유효성 검사는 모든 애플리케이션 계층에서 발생하는 공통 작업으로, 동일한 유효성 검사 논리가 각 계층에 구현되어 코드의 중복이 발생한다.

이러한 중복을 피하기 위해 각 계층을 도메인 모델로 묶어주고, 도메인 계층에서 Bean Validation Annotation을 사용하여 애플리케이션 전 계층에서 도메인 객체를 검증할 수 있다.

이번에는 Bean Validation Annotation을 이용하여 데이터를 검증하는 방법에 대해 알아보도록 하자. (이미지 출처 : Hibernate Validator - Reference Guide)

2. 개발 환경

  • Java 11

  • Spring Boot 2.5.3

3. build.gradle

1
2
3
4
5
dependencies {
    ...
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    ...
}

4. Bean Validation Annotation 추가

[PasswordForm.java]

1
2
3
4
5
6
7
8
9
@Data
public class PasswordForm {

    @Length(min = 8, max = 20)
    private String newPassword;

    @Length(min = 8, max = 20)
    private String newPasswordConfirm;
}

@AssertFalse : 값이 false인지 확인

@AssertTrue : 값이 true인지 확인

@DecimalMax(value=, inclusive=) : value로 설정한 값보다 작은지 확인 (inclusive가 true이면 value 값도 인정)

@DecimalMin(value=, inclusive=) : value로 설정한 값보다 큰지 확인 (inclusive가 true이면 value 값도 인정)

@Digits(integer=, fraction=) : 정해진 자릿수 이하인지 확인 (integer는 허용 가능한 정수 자릿수, fraction은 허용 가능한 소수점 이하 자릿수)

@Email : 이메일 형식인지 확인

@Future : 해당 시간이 미래인지 확인

@FutureOrPresent : 해당 시간이 현재 또는 미래인지 확인

@Max(value=) : 설정한 값보다 작은지 확인

@Min(value=) : 설정한 값보다 큰지 확인

@NotBlank : null이 아니고 한 개 이상의 문자를 포함하는지 확인(공백 제외)

@NotEmpty : null이 아니고 한 개 이상의 문자를 포함하는지 확인(공백 포함)

@NotNull : null이 아닌지 확인

@Negative : 음수인지 확인

@NegativeOrZero : 음수이거나 0인지 확인

@Null : null인지 확인

@Past : 해당 시간이 과거인지 확인

@PastOrPresent : 해당 시간이 현재 또는 과거인지 확인

@Pattern(regex=, flags=) : 해당 정규식을 만족하는지 확인

@Positive : 양수인지 확인

@PositiveOrZero : 양수이거나 0인지 확인

@Size(min=, max=) : 해당 범위의 값인지 확인(max, min 값 포함)

5. Validator 인터페이스 구현

[PasswordFormValidator.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class PasswordFormValidator implements Validator {

    @Override
    public boolean supports(Class<?> clazz) {
        return PasswordForm.class.isAssignableFrom(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        PasswordForm passwordForm = (PasswordForm) target;
        if(!passwordForm.getNewPassword().equals(passwordForm.getNewPasswordConfirm())) {
            errors.rejectValue("newPassword", "wrong.value", "입력한 새 패스워드가 일치하지 않습니다.");
        }
    }
}

Line 4 : 검증 가능한 타입의 객체인지 확인하는 메서드

Line 9 : 검증을 위한 메서드로, target을 검증한 후 에러가 있으면 errors에 담음

Line 10 ~ 13 : newPassword와 newPasswordConfirm의 값이 일치하지 않는 경우 검증 실패 처리

void rejectValue(String field, String errorCode, String defaultMessage)
해당 에러에 대한 정보 추가
String field 에러 발생 필드
String errorCode 해당 에러에 대한 에러코드
String defaultMessage 해당 에러에 대한 Default 메시지

6. 검증대상 직접 등록

메서드마다 검증을 원하는 객체를 전달하여 직접 검증 요청을 하는 방법니다.

[AccountSettingsController.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Slf4j
@RestController
public class AccountSettingsController {

    @PostMapping("/password")
    public void updatePassword(@Valid PasswordForm passwordForm, Errors errors) {
        PasswordFormValidator passwordFormValidator = new PasswordFormValidator();
        passwordFormValidator.validate(passwordForm, errors);

        if(errors.hasErrors()) {
            log.info("fail!!");

            errors.getAllErrors().forEach(e -> {
                System.out.println(e.getDefaultMessage());
            });

            return;
        }

        log.info("success!!");
    }
}

Line 8 : 검증을 원하는 객체를 전달하고, 에러 발생시 errors에 에러 정보를 담음

7. InitBinder를 통한 검증대상 자동 등록

검증대상을 직접 등록 하는 방법은 코드의 중복도 발생하고 번거롭다. @InitBinder를 사용하면 검증대상을 자동으로 등록할 수 있다.

[AccountSettingsController.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Slf4j
@RestController
public class AccountSettingsController {

    @InitBinder("passwordForm")
    public void passwordFormInitBinder(WebDataBinder webDataBinder) {
        webDataBinder.addValidators(new PasswordFormValidator());
    }

    @PostMapping("/password")
    public void updatePassword(@Valid PasswordForm passwordForm, Errors errors) {
        if(errors.hasErrors()) {
            log.info("fail!!");
            return;
        }

        log.info("success!!");
    }

Line 5 : @InitBinder를 사용하여 검증대상 지정

Line 7 : 어떤 Validator를 사용하여 검증할지 지정

Updated:

Leave a comment