[Spring] Bean Validation
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를 사용하여 검증할지 지정
Leave a comment