날짜에 대한 Validation을 진행하고자 할 때 우리는
public class User {
private String name;
private int age;
@Email
private String email;
@Pattern(regexp = "^\\d{2,3}-\\d{3,4}-\\d{4}$", message = "핸드폰 번호의 양식과 맞지 않습니다. 01x-xxx(x)-xxxx")
private String phoneNumber;
@Size(min = 6, max = 6)
private String reqYearMonth; //yyyyMM
//getter, setter, toString
}
와 같이 @Size를 통해서 검증할 수있지만 저런 형식의 경우 123456로 들어온경우도 통과가 될 것이다. 그래서 @AssertTrue를 통해서 Validation을 해보겠다.
@AssertTrue
public boolean isReqYearMonthValidation() {
try {
LocalDate localDate = LocalDate.parse(getReqYearMonth() + "01";, DateTimeFormatter.ofPattern("yyyyMMdd"));
} catch (Exception e) {
return false;
}
return true;
}
AssertTrue/False의 경우 메소드명을 is로 만들어줘야한다.
User 클래스에 위와같은 메소드를 추가해주고 실행하면
reqYearMonth에 날짜 형식과 맞지않은 값을 보냈으므로 위와같은 결과가 나온다.
그런데 AssertTrue는 다른 클래스를 만들경우 다시 또 메소드르 만들어줘야 하기때문에 중복된 코드가 여러번 나올 수 있다. 이를 해결하기 위해 Custom Annotation을 만들어서 Validation을 할 수 있도록 해보겠다.
먼저 @Email이 어떻게 생겼는지 확인해보면 ( @Email annotation을 ctrl+클릭)
위와 같이 @Constraint, @Target, @Retention이 들어가있고 변수로는 message, groups등등이 들어가있다. 이걸 참고해서 나만의 annotation을 만들어보겠다.
우선 나는 annotation 패키지를 만들어서 annotation형식의 YearMonth파일을 생성해주었다.
@Constraint(validatedBy = { YearMonthValidator.class })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface YearMonth {
String message() default "yyyyMM 형식에 맞지않습니다.";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
String pattern() default "yyyyMMdd";
}
그리고 위와같이 작성하고 validator패키지를 만들고 YearMonthValidator 클래스를 생성한 뒤
public class YearMonthValidator implements ConstraintValidator<YearMonth, String> {
private String pattern;
@Override
public void initialize(YearMonth constraintAnnotation) {
this.pattern = constraintAnnotation.pattern();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// yyyyMM
try {
LocalDate localDate = LocalDate.parse(value + "01", DateTimeFormatter.ofPattern(this.pattern));
} catch (Exception e) {
return false;
}
return true;
}
}
이제 User클래스의 reqYearMonth 변수에 내가 만든 @YearMonth를 붙여주면 작동하는 것을 확인 할 수 있다.
@YearMonth
private String reqYearMonth;
그리고 만약 다른 오브젝트가 멤버변수로 추가된다면 validation의 작동이 제대로 되는지에 대해서 알아보자.
public class Car {
@NotBlank
private String name;
@NotBlank
@JsonProperty("car_number")
private String carNumber;
@NotBlank
@JsonProperty("TYPE")
private String type;
}
위와 같은 Car클래스가 있고, User클래스에서 List형식의 cars가 오브젝트를 멤버변수로 받을 때 Car의 Validation이 제대로 작동할까?
private List<Car> cars;
제대로 작동 하지않는다!! 제대로 Validation이 작동하려면
@Valid를 붙여줘야한다.
@Valid
private List<Car> cars;