앞서 정리한 @Valid에서 @Password라는 어노테이션이 있었다. 이는 Validation의 기능이 아니고 커스텀으로 어노테이션으로 직접 만든 기능이다.
어떻게 만들었는가 정리해보겠다.
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PasswordConstraintsValidator.class)
public @interface Password {
String message() default "Invalid password";
Class[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
앞서 Constratint 어노테이션에서 말했듯 실제 검증 로직을 제공하는 클래스이다.
public class PasswordConstraintsValidator implements ConstraintValidator<Password, String> {
@Override
public boolean isValid(String password, ConstraintValidatorContext context) {
PasswordValidator passwordValidator = new PasswordValidator(
Arrays.asList(
//비밀번호 길이가 8~20 사이여야 한다.
new LengthRule(8, 20),
//적어도 하나의 대문자가 있어야 한다.
new CharacterRule(EnglishCharacterData.UpperCase, 1),
//적어도 하나의 소문자가 있어야 한다.
new CharacterRule(EnglishCharacterData.LowerCase, 1),
//적어도 하나의 숫자가 있어야 한다.
new CharacterRule(EnglishCharacterData.Digit, 1),
//적어도 하나의 특수문자가 있어야 한다.
new CharacterRule(EnglishCharacterData.Special, 1),
//공백문자는 허용하지 않는다.
new WhitespaceRule()
)
);
RuleResult result = passwordValidator.validate(new PasswordData(password));
if (result.isValid()) {
return true;
}else {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(String.join(",", passwordValidator.getMessages(result)))
.addConstraintViolation();
return false;
}
}
}