여러 개 필드값 체크 validator
여러 개의 필드값을 체크하는 로직을 커스텀 밸리데이터로 구현한다.
- 멤버 검색을 위해 이름, 이메일, 전화번호 3가지 검색어를 사용할 수 있다.
- 3가지 검색어 중에서 하나만 입력하면 정상 수행된다.
- 검색어가 입력되지 않은 경우에는 400 Bad Request 코드를 반환한다.
- 어노테이션 생성
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Constraint(validatedBy = SearchUserConditionValidator.class)public @interface SearchUserCondition {String message() default "검색 조건이 설정되지 않았습니다.";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};String name();String email();String mobile();}
- ConstraintValidator 구현제 생성
@Slf4jclass SearchUserConditionValidator implements ConstraintValidator<SearchUserCondition, Object> {private String nameFieldName;private String emailFieldName;private String mobileFieldName;@Overridepublic void initialize(final SearchUserCondition constraintAnnotation) {nameFieldName = constraintAnnotation.name();emailFieldName = constraintAnnotation.email();mobileFieldName = constraintAnnotation.mobile();}@Overridepublic boolean isValid(final Object object, final ConstraintValidatorContext constraintValidatorContext) {final String name = getFieldValue(object, nameFieldName);final String email = getFieldValue(object, emailFieldName);final String mobile = getFieldValue(object, mobileFieldName);log.info("검색 조건 유효성 검사 - 이름: {}, 이메일: {}, 전화번호: {}", name, email, mobile);return !StringUtils.isAllBlank(name, email, mobile);}private String getFieldValue(final Object object, final String fieldName) {try {final Field field = object.getClass().getDeclaredField(fieldName);field.setAccessible(true);return (String) field.get(object);} catch (NoSuchFieldException | IllegalAccessException e) {log.error("Error accessing field: {}", fieldName, e);return null;}}}
- 요청 DTO 클래스의 멤버에 제약 설정
any request dto class any request dto class @Getter@Setter@ToString@Builder@SearchUserCondition(name = "searchName", email = "searchEmail", mobile = "searchMobile")public class SearchUserConditionRequest {@Schema(description ="이름 검색 키워드")@Length(min = 2)private String searchName;@Schema(description ="이메일 검색 키워드")@Length(min = 2)private String searchEmail;@Schema(description ="전화번호 검색 키워드")@Length(min = 2)private String searchMobile;} - Controller 메소드에 Valid(Validated) 어노테이션 추가
any controller class any controller class @Operation(summary = "다중 컬럼 유효성 검사 테스트", description = "다중 컬럼 유효성 검사 테스트 API")@PostMapping("/multi-value-validation-test")public ResponseEntity<ResponseDto<Void>> testMultiValueValidation(@Valid @RequestBody final SearchUserConditionRequest param) {final ResponseDto<Void> response = new ResponseDto<>();return ResponseEntity.ok(response);} - 테스트
any test class any test class @DisplayName("멀티 컬럼 유효성 체크 테스트(1개 검색조건 설정)")@Testvoid testOneSearchKeyword() {final SearchUserConditionRequest param = SearchUserConditionRequest.builder().searchMobile("010-1234-5678").build();given().spec(jsonRequestSpecification).body(param).when().post("/spring-boot/multi-value-validation-test").then().statusCode(HttpStatus.SC_OK).log().all();}@DisplayName("멀티 컬럼 유효성 체크 테스트(2개 검색조건 설정)")@Testvoid testTwoSearchKeyword() {final SearchUserConditionRequest param = SearchUserConditionRequest.builder().searchMobile("010-1234-5678").searchName("홍길동").build();given().spec(jsonRequestSpecification).body(param).when().post("/spring-boot/multi-value-validation-test").then().statusCode(HttpStatus.SC_OK).log().all();}@DisplayName("멀티 컬럼 유효성 체크 테스트(3개 검색조건 설정)")@Testvoid testThreeSearchKeyword() {final SearchUserConditionRequest param = SearchUserConditionRequest.builder().searchMobile("010-1234-5678").searchName("홍길동").searchEmail("example@example.com").build();given().spec(jsonRequestSpecification).body(param).when().post("/spring-boot/multi-value-validation-test").then().statusCode(HttpStatus.SC_OK).log().all();}@DisplayName("멀티 컬럼 유효성 체크 테스트(검색 키워드 없음)")@Testvoid testMultiValueValidationFailed() {final SearchUserConditionRequest param = SearchUserConditionRequest.builder().build();given().spec(jsonRequestSpecification).body(param).when().post("/spring-boot/multi-value-validation-test").then().statusCode(HttpStatus.SC_BAD_REQUEST).log().all();}