매주 스프링 부트 핵심 가이드 를 읽으며 이전에 궁금했거나, 새롭게 알게 된 내용들을 정리할 예정이다.
(이번 주는 10장을 읽었다.)
어플리케이션의 비즈니스 로직이 올바르게 동작하려면 데이터를 사전 검증하는 작업이 필요한데, 이를 유효성 검사 또는 데이터 검증이라 부른다. 의도한 형식으로 값이 들어오는지 체크하는 과정이 예시라고 할 수 있다.
public class ValidRequestDto {
@NotBlank
String name;
@Email
String email;
@Pattern(regexp = "정규식")
String phoneNumber;
@Min(value = 20)
@Max(value = 40)
int age;
@Size(min = 0, max = 40)
String description;
@Positive
int count;
@AssertTrue
boolean booleanCheck;
}
위와 같은 DTO 클래스가 있다. 각 필드에 어노태이션을 선언함으로써 유효성 검사를 위한 조건을 설정한다. 대표적인 어노태이션은 다음과 같다.
@Null
: null
만 허용한다.@NotNull
: null
을 허용하지 않는다. ""
, " "
는 허용한다.@NotEmpty
: ""
을 허용하지 않고 " "
는 허용한다.@NotBlank
: ""
, " "
둘 다 허용하지 않는다.@Min/Max(value = $number),
: $number
이상/이하의 값을 허용한다.@Positive/Negative
: 양수/음수 를 허용한다.@PositiveOrZero/NegativeOrZero
: 0을 포함한 양수/음수 를 허용한다.@Future/Past
: 현재보다 미래/과거 의 날짜를 허용한다.@FutureOrPresent/PastOrPresent
: 현재를 포함한 미래/과거 의 날짜를 허용한다.@Email
: 이메일 형식이 올바른지 검사하며 ""
을 허용한다.@AssertTrue/AssertFalse
: true
/false
인지 체크하며 null
값은 체크하지 않는다.@Size(min = $number1, max = $number2)
: $number1
이상 $number2
이하의 범위를 허용한다.@Pattern(regexp = "정규식")
: 정규식을 검사한다. java.util.regex.Pattern
패키지의 컨벤션을 따른다.위처럼 DTO 객체를 선언해준 후 컨트롤러의 @RequestBody
앞에 @Valid
를 달아줘야 설정한 유효성 검사를 수행한다.
@PostMapping("/valid")
public ResponseEntity<String> checkValidation(
@Valid @RequestBody ValidRequestDto validRequestDto) {
...
}
규칙에 맞게 요청하면 http 응답으로 200 OK
메세지가 뜨고, 아닌 경우 400 bad request
가 뜨며 로그에서 문제가 있는 부분을 확인할 수 있다.
방금까지 유효성 검사를 위해 @Valid
를 사용했다. 스프링에서는 @Validated
을 지원하며, @Valid
의 기능을 포함하고 있기 때문에 변경 가능하다. 유효성 검사를 그룹으로 묶어 대상을 특정 가능하다. 그룹은 코드가 없는 인터페이스의 형태로 생성한다.
public interface ValidationGroup {
}
그룹을 설정하는 법은 DTO 객체의 어노태이션에 그룹을 명시해주면 된다.
// ValidRequestDto
...
@Min(value = 20, groups = ValidationGroup.class)
@Max(value = 40, groups = ValidationGroup.class)
int age;
...
컨트롤러에서 활용하는 법은 @Valid
를 사용한 것과 똑같이 같은 자리에 그룹 클래스를 포함해 설정해주면 된다.
@PostMapping("/validated/group")
public ResponseEntity<String> checkValidation2(
@Validated(ValidationGroup.class) @RequestBody ValidRequestDto validRequestDto) {
...
}
이렇게 그룹을 명시하여 실행하면 그룹에 포함된 필드만 유효성 검사를 실시한다. 반대로 그룹을 지정하지 않으면 groups
를 설정하지 않은 필드에 대해서 유효성 검사를 실시한다.
인터페이스 ConstraintValidator
를 구현하는 클래스를 생성하는 방식으로 구현한다. 그리고 이 클래스를 커스텀 어노태이션에 @Constraint(validatedBy = Validator.Class)
어노태이션을 지정해주면 된다.