Spring Boot Custom Validation

박민주·2024년 1월 10일
0
  1. AssertTrue /False 와 같은 method지정을 통해서 custom logic 적용가능
  2. ConstraintValidator를 적용하여 재사용이 가능한 custom logic 적용 가능

날짜에 대한 Validation을 진행하고자 할 때 우리는

User

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파일을 생성해주었다.

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 클래스를 생성한 뒤

  • implements ConstraintValidator
    - implements ConstraintValidator<YearMonth, String>
    - 입력받을 어노테이션과 데이터의 형식 지정
  • initialize()
    - 메서드 시작 시의 초기 설정
  • isValid()
    - 데이터 검사 메소드
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의 작동이 제대로 되는지에 대해서 알아보자.

car

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;
profile
개발자 되고싶다..

0개의 댓글