스프링 입문

[스프링 입문] 6.2 Spring Boot Custom Validation

코딩펭귄 2024. 1. 8. 23:51

Custom Validation

1. AssertTrue / False 와 같은 method지정을 통해 Custom Logic 적용 가능(재사용 불가)

2. CustomValidator를 적용하여 재사용이 가능한 Custom Logic 적용가능

 

 

@AssertTrue -> "is" 라는 키워드로 항상 메소드가 시작해야 됨

@AssertTrue(message = "yyyyMM의 형식에 맞지 않습니다.")
    public booldean isReqYearMonthValidation(){
        System.out.println("assert true call");
        try{
            LocalDate localDate = LocalDate.parse(getReqYearMonth() + "01", DateTimeFormatter.ofPattern("yyyyMMdd"));
        }catch (Exception e){
            return false;
        }
        return true;
    }

 

 

YearMonth 라는 annotation 만들기(custom) 예제 (6.1 예제 참고)

import com.example.validation.validator.YearMonthValidator;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Constraint(validatedBy = {YearMonthValidator.class}) //YearMonthValidator의 클래스를 가지고 검사가 이루어짐
@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";
}
import com.example.validation.dto.User;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;


@RestController
@RequestMapping("/api")
public class ApiController {

    @PostMapping("/user")
    public ResponseEntity user(@Valid @RequestBody User user, BindingResult bindingResult){

        if(bindingResult.hasErrors()){
            StringBuilder sb = new StringBuilder();
            bindingResult.getAllErrors().forEach(objectError -> {
                FieldError field = (FieldError) objectError;
                String message = objectError.getDefaultMessage();

                System.out.println("field : "+field.getField());
                System.out.println(message);

                sb.append("field : "+field.getField());
                sb.append("message : "+message);

            });

            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(sb.toString());
        }
        return ResponseEntity.ok(user);
    }

}

 

* 특정 클래스, 변수에 대해 검사를 하고싶다?(그것이 object 형태라면) : @Valid 꼭 붙여줘야됨 

dto-User 파일에 추가하기
@Valid // 검사하고싶다면 꼭 Valid 어노테이션 붙여주기
private List<Car> cars;
import com.example.validation.annotation.YearMonth;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

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) {

        // value값이 확인하고자 하는 yyyyMM
        try{ //value+'01' 로 하는 이유 : 자동적으로 month에대해 검색이 되기 때문(local date이기 때문)
            LocalDate localDate = LocalDate.parse(value+"01" , DateTimeFormatter.ofPattern(this.pattern));
        }catch (Exception e){
            return false;
        }
        
        return true;
    }
}
import com.fasterxml.jackson.annotation.JsonProperty;

public class Car {

    @NotBlank
    private String name;

    @NotBlank
    @JsonProperty("car_number")
    private String carNumber;

    @NotBlank
    @JsonProperty("TYPE") //대문자
    private String type;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCarNumber() {
        return carNumber;
    }

    public void setCarNumber(String carNumber) {
        this.carNumber = carNumber;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", carNumber='" + carNumber + '\'' +
                ", type='" + type + '\'' +
                '}';
    }
}