메서드를 사용하거나, 정규식과 비교해주는 어노테이션을 외에도 별도의 정규식을 만들어서 사용 할 수 있다.
별도의 정규식을 추가하는 필요성?
보통 날짜 부분에서 많이 사용된다. String 형으로 받아오게되는데, 명확히 확인 될 수 있는 정규식이 없다.
예시로 년도와 달 6글자를 받는 필드가 있다고 할때, 조건을 더 추가해주지 않으면 글자 수가 맞다면 날짜가 일치 하지 않아도 실행에 성공하게 된다. 각 사이트의 비즈니스 로직에 맞는 정규식이 필요하다.
@Size(min=6,max = 6,message = "날짜를 정확하게 입력해주세요 ex ) yyyyMM")
private String reqYearMonth;
1. @AssertTrue/False 어노테이션 사용
필드를 가져와서 정해진 패턴과 비교해주는 별도의 메서드를 만들어줄 수 있다.
@AssertTrue 어노테이션, is 가 포함된 메서드 명을 반드시 넣어주어야한다.
- 파싱이 잘되면 true를 반환하여 값이 노출되고, 파싱이 실패한다면 false를 반환하여 에러 메시지가 노출된다.
- 내부에 바로 받아주는 필드의 명을를 적게 되어 재활용이 불가능하다.
📑 User.java
@AssertTrue
public boolean isReqYearMonthValidation(){
this.reqYearMonth=getReqYearMonth()+"01";
try {
//실제 날짜 패턴과 비교해주는 부분
LocalDate localDate = LocalDate.parse(this.reqYearMonth, DateTimeFormatter.ofPattern("yyyyMM"));
}catch (Exception e){
return false;
}
return true;
}
2. 재사용이 가능한 커스텀 어노테이션을 생성.
정규식을 실행해주는 비즈니스 로직이 들어간 어노테이션을 직접 만들어 사용이 가능하다.
1) 어노테이션 인터페이스
📑 YearMonth.java
package com.example.validation.anotation;
import com.example.validation.Validator.YearMontValidator;
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 = {YearMontValidator.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 "yyyyMM"; // 어떤 형식으로 받아줄지 지정하여 주는 부분. - 기본패턴
}
2) 실제 정규식 로직이 들어간 클래스
ConstraintValidator 객체를 통해 어노테이션 인터페이스와 받아오는 문자를 넣어서 실행 결과를 반환해주는 클래스
📑 YearMonthValidator.java
package com.example.validation.Validator;
import com.example.validation.anotation.YearMonth;
import javax.swing.*;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class YearMontValidator implements ConstraintValidator<YearMonth,String> {
String pattern;
@Override
public void initialize(YearMonth constraintAnnotation) {
this.pattern = constraintAnnotation.pattern();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
//value yyyyMM value+"01"
try {
LocalDate localDate = LocalDate.parse(value+"01", DateTimeFormatter.ofPattern("yyyyMM"));
}catch (Exception e){
return false;
}
return true;
}
}
3) 사용될 필드 부분에서 어노테이션 선언
📑 User.java
@YearMonth
private String reqYearMonth;
4) 컨트롤러에서 객체 받아오는 부분
📑 ApiController.java
package com.example.validation.controller;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
@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 = field.getDefaultMessage();
System.out.println("필드 :" + 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);
}
}
※ 만약 객체 클래스 안에 다른 객체가 있고 그안에서도 validation을 검사해줘야할때, 객체 필드에도 @Valid 어노테이션을 선언해주어야한다.
📑 user.java
@Valid
private List<Car> cars;
📑 Car.java
@NotNull
private carName;
'BackEnd > Spring Boot' 카테고리의 다른 글
[ Spring Boot ] Exception 예외 처리 방법 (0) | 2023.03.10 |
---|---|
[ Spring ] Test Code - Controller 전체를 테스트하는 방법 (0) | 2023.03.09 |
[ Spring Boot ] Validation (1) (0) | 2023.03.08 |
[ Spring ] Annotation 정리 (1) (0) | 2023.03.07 |
[ Spring ] Aop 관점 지향 프로그램 (0) | 2023.03.07 |