[TIL 19] Spring 기초 공부_9

돗치·2024년 3월 5일

Spring Validation

저번에는 중복 조건과 같이 조금 애매한 부분을 처리할 수 없었다.
annotation을 커스텀할 수 있다.

닉네임, 이름 둘 중 하나만 있어도 통과시켜줄 수 있는 것을 만들어보자

AssertTrue annotation은 이 is 라는 boolean을 return하는 메소드에 반드시 붙여줘야 한다.
Name Object가 null이 아니어야 되고 name이 blank가 아니여야 통과할 수 있다.

    private String name;
    private String nickName;

    @AssertTrue(message = "name or nickname 은 존재해야 합니다.")
    public boolean isNameCheck(){
        if(Objects.nonNull(name) && !name.isBlank()) {
            return true;
        }
        if(Objects.nonNull(nickName) && !nickName.isBlank()) {
            return true;
        }
        return false;
    }
  "resultCode": "",
  "resultMessage": "",
  "data": {
    "name": "",
    "nickname": "",
    "age": 20,
    "password": "1111",
    "email": "meow@gmail.com",
    "phone_number": "123-456-7890",
    "register_at": "2025-01-01T13:00:00"
  },
  "error": {
    "errorMessage": []
  }
}

json을 위처럼 send했더니 error가 제대로 떴다.

name에 이름을 넣으면 잘 전송된다.

이번엔 phonenumber에 대한 코드를 작성해보자

@Constraint(validatedBy = {PhoneNumberValidator.class})은 어떤 클래스로 검증을 할 것이냐 라고 해서 validator을 지정해주는 것이다.
@Target({ElementType.FIELD})는 변수에다가 붙일 것이기 때문에 field만 붙이자.
@Retention(RetentionPolicy.RUNTIME)은 Policy가 실행 중에만 annotation이 동작하는 것이다.

@Constraint(validatedBy = {PhoneNumberValidator.class})
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PhoneNumber {
    String message() default "핸드폰 번호 양식에 맞지 않습니다. ex) 000-0000-0000";
    String regexp() default "^\\d{2,3}-\\d{3,4}-\\d{4}$";

    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

이제 phonenumber를 검증해주는 클래스를 작성해보자

public class PhoneNumberValidator implements ConstraintValidator<PhoneNumber, String> {

    //    초기화할때 default 패턴을 가져오기 위해
    private String regexp;

    @Override
    public void initialize(PhoneNumber constraintAnnotation) {
        this.regexp = constraintAnnotation.regexp();
    }

    @Override   //어떤 값을 검증할 것인지는 value에 할당된 값이 넘어 오고, 그 값을 검증해줘야 한다.
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null) {
            return true; // null 값을 허용하는 경우 true 반환
        }
        boolean result = Pattern.matches(regexp, value);
        return result;
    }
}

그리고 저번에 했던 정규식을 정해놓은 @Pattern annotation을 지우고 @PhoneNumber annotation을 달아보자

    @PhoneNumber
    private String phoneNumber;

그러면 400error가 뜨면서 errorMessage도 제대로 뜨게 된다.

이번엔 날짜 검증, YearMonth를 만들어보자
UserRegisterRequest에 아래 코드를 추가하고

    @YearMonth(pattern = "yyyy-MM")
    private String birthDayYearMonth;
package com.example.validation.annotation;

import com.example.validation.validator.PhoneNumberValidator;
import com.example.validation.validator.YearMonthValidator;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Constraint(validatedBy = {YearMonthValidator.class})
@Target({ElementType.FIELD})   
@Retention(RetentionPolicy.RUNTIME) 
@NotBlank

public @interface YearMonth {
    String message() default "Year Month 양식에 맞지 않습니다. ex) 230101";
    String pattern() default "yyyyMMDD";

    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
package com.example.validation.validator;


import com.example.validation.annotation.PhoneNumber;
import com.example.validation.annotation.YearMonth;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;


import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.regex.Pattern;

public class YearMonthValidator implements ConstraintValidator<YearMonth, String> {

    private String pattern;

    @Override
    public void initialize(YearMonth constraintAnnotation) {
        this.pattern = constraintAnnotation.pattern();
    }

    @Override   //어떤 값을 검증할 것인지는 value에 할당된 값이 넘어 오고, 그 값을 검증해줘야 한다.
    public boolean isValid(String value, ConstraintValidatorContext context) {

        var reValue = value + "01";
        var rePattern = pattern + "dd";

        try {
            LocalDate date = LocalDate.parse(value, DateTimeFormatter.ofPattern(value));
            System.out.println(date);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

코드를 위처럼 작성하고 우선 틀린 양식의 YearMonth를 보내보자

{
  "resultCode": "",
  "resultMessage": "",
  "data": {
    "name": "sdf",
    "nickname": "dsf",
    "age": 20,
    "password": "1111",
    "email": "meow@gmail.com",
    "phone_number": "010-1234-4564",
    "register_at": "2025-01-01T13:00:00",
    "birth_day_year_month": "202301"
  },
  "error": {
    "errorMessage": []
  }
}

400 에러가 뜨고

제대로 넣으면 200 ok 가 뜨면서 잘 온다.

0개의 댓글