DTO 유효성 검증 (Validation) - (1)
by mignon25유효성 검증을 위한 의존 라이브러리 추가
// build.gradle
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation'
...
}
유효성 검증 대상 및 제약 사항 확인 - MemberPostDto
// MemberPostDto
@Getter
public class MemberPostDto {
private String email;
private String name;
private String phone;
}
위와 같은 DTO 객체의 멤버 변수에 대해 다음과 같은 제약 사항이 존재한다고 가정해보자.
<MemberPostDto 유효성 검증 제약 사항>
- email (이메일 주소)
- 값이 비어있지 않거나(null X) 공백이 아니어야 한다.
- 유효한 이메일 주소 형식이어야 한다.
- name (이름)
- 값이 비어있지 않거나(null X) 공백이 아니어야 한다.
- phone (휴대폰 번호)
- 값이 비어있지 않거나(null X) 공백이 아니어야 한다.
- 010-xxx-xxxx 또는 010-xxxx-xxxx 의 형식의 문자열이어야 한다.
Validation 적용하기
javax.validation.constraints 에 정의된 애너테이션 및 커스텀 애너테이션을 통해 validation을 적용할 수 있다.
1. MemberPostDto 에 Validation 적용
// MemberPostDto
@Getter
public class MemberPostDto {
@NotBlank
@Email
private String email;
@NotBlank(message = "이름은 공백이 아니어야 합니다.")
private String name;
@Pattern(regexp = "^010-\\d{3,4}-\\d{4}$",
message = "휴대폰 번호는 010으로 시작하는 11자리 숫자와 '-'로 구성되어야 합니다.")
private String phone;
}
@NotBlank
- null 값, 공백(""), 스페이스(" ") 모두 허용하지 않는다.
- 유효성 검증에 실패하면 에러 메세지가 콘솔에 출력된다.
- 유효한 이메일 주소인지 검증
- 유효성 검증에 실패하면 내장된 디폴트 에러 메세지가 콘솔에 출력된다.
- (주의) 최상위 도메인이 빠진 aaa@bbbb 같은 형태도 유효성 검증에 통과된다.
=> 필요하다면 추가적인 조건을 지정해줄 것. (정규 표현식 또는 커스텀 애너테이션)
@Pattern
- 휴대폰 번호의 형식을 정규 표현식을 통해 검증
<그 밖의 Validation 애너테이션들 >
Jakarta Bean Validation : 표준 스펙에서 지원하는 유효성 검증을 위한 내장 애너테이션
@Range(min = 10000, max = 50000)
- null 허용
- 원하는 범위를 최소값과 최대값을 통해 지정할 수 있다.
@Positive, @PositiveOrZero
- null 허용
- 양수 또는 0이상의 수 허용
@Min(10), @Max(10)
- null 허용
- 최소값 및 최대값 지정
<정규 표현식 예시>
regexp = "^\\S+(\\s?\\S+)*$"
- 문자열의 처음은 무조건 공백이 아닌 문자
- 이후 ((공백 문자 0개 또는 1개)(공백이 아닌 문자 1개 이상)) 패턴이 0개 이상 온다.
- ^ : 문자열의 시작
- \\S : 공백이 아닌 문자
- + : 바로 앞의 패턴 1개 이상
- () : 그룹화
- \\s : 공백 문자
- ? : 바로 앞 패턴 0개 또는 1개
- \\S+ : 공백이 아닌 문자 1개 이상
- ()* : * 앞의 패턴 0개 이상
- $ : 문자열의 끝
2. Controller에서 Validation 적용 설정
Dto 클래스 앞에 @Valid 추가
@RestController
@RequestMapping("/v1/coffees")
public class CoffeeController {
@PostMapping
public ResponseEntity postCoffee(@Valid @RequestBody CoffeePostDto coffeePostDto) {
return new ResponseEntity<>(coffeePostDto, HttpStatus.CREATED);
}
...
}
쿼리 파라미터 및 @Pathvariable 에 대한 유효성 검증
1. Controller 의 클래스 레벨에 @Validated 추가
2. 검증할 쿼리 파라미터 또는 @Pathvaiable 애너테이션 뒤에 원하는 validation annotation 추가
@RestController
@RequestMapping("/v1/coffees")
@Validated // 추가
public class CoffeeController {
@PatchMapping("/{coffee-id}")
public ResponseEntity patchCoffee(
@PathVariable("coffee-id") @Positive long coffeeId, // 추가
@Valid @RequestBody CoffeePatchDto coffeePatchDto) {
return new ResponseEntity<>(coffeePatchDto, HttpStatus.OK);
}
...
}
- @Validated
- @PathVariable("coffee-id") @Positive long coffeeId,
Custom Validator 를 사용한 유효성 검증
1. Custom Validor 를 사용하기 위한 Custom Annotation 정의
2. 정의한 Custom Annotation 에 바인딩되는 Custom Validator 구현
3. 유효성 검증이 필요한 DTO 클래스의 멤버 변수에 Custom Annotation 추가
1. Custom Annotation 정의
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {NotSpaceValidator.class}) // (1)
public @interface NotSpace {
String message() default "공백이 아니어야 합니다"; // (2)
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
- (1) : 바인딩되는 Validator 클래스
- (2) : 애너테이션 추가시 별도로 message를 정의하지 않았을 때 유효성 검증 실패 시, 디폴트로 표시하는 메세지
2. Custom Validator 구현
public class NotSpaceValidator implements ConstraintValidator<NotSpace, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return value == null || StringUtils.hasText(value);
}
}
- CustomValidator를 구현하기 위해서는 ConstraintValidator 인터페이스를 구현해야 한다.
- ConstraintValidator<NotSpace, String>
- NotSpace : CustomValidator와 매핑된 Custom Annotation
- String : Custom Annotation 으로 검증할 대상 멤버변수의 타입
- value의 타입도 검증 대상 멤버변수 타입으로 일치시켜준다.
- isValid() 메서드에 유효성 검증 로직 구현
3. 유효성 검증을 위해 Custom Annotation 추가
@Getter
public class MemberPatchDto {
private long memberId;
@NotSpace(message = "회원 이름은 공백이 아니어야 합니다") // (1)
private String name;
@Pattern(regexp = "^010-\\d{3,4}-\\d{4}$",
message = "휴대폰 번호는 010으로 시작하는 11자리 숫자와 '-'로 구성되어야 합니다")
private String phone;
}
'Spring' 카테고리의 다른 글
| [예외 처리] 비즈니스 로직에 대한 예외 처리 (0) | 2023.04.20 |
|---|---|
| [예외 처리] @ExceptionHandler를 이용한 예외 처리 (0) | 2023.04.20 |
| HTTP 요청/응답에서의 DTO(Data Transfer Object) (0) | 2023.04.17 |
| Rest Client, RestTemplate (0) | 2023.04.17 |
| [Spring MVC] API 계층 적용하기 (Prac Project - 1. 커피 주문 애플리케이션 시작) (0) | 2023.04.16 |
블로그의 정보
Mignon'S Dev Log
mignon25