데이터베이스에 올바른 데이터만 저장하기 위해서는 DTO에 유효성 검사를 해야한다.
물론 프론트에서도 유효성 검사를 해야하나 , API 서버를 통해서 데이터를 받는 경우에는 프론트에서 유효성 검사를 할 수 없다.
따라서 백엔드에서 유효성 검사를 해야한다.
Spring 에서는 DTO 에 대한 유효성 검사를 어노테이션을 통해 쉽게 할 수 있다.
@Data
public class UserDto {
@NotBlank
private String name;
@NotBlank
private String email;
@NotBlank
private String password;
}
위와 같이 DTO에 유효성 검사를 할 어노테이션을 추가하면 된다.
스프링에서 제공하는 유효성 검사 어노테이션은 다음과 같다.
어노테이션 | 설명 |
---|---|
@Null | null 인지 검사 |
@NotNull | null 이 아닌지 검사 |
@AssertTrue | true 인지 검사 |
@AssertFalse | false 인지 검사 |
@Min(value) | 최소값 검사 |
@Max(value) | 최대값 검사 |
@DecimalMin(value) | 최소값 검사 |
@DecimalMax(value) | 최대값 검사 |
@Size(max, min) | 최소, 최대값 검사 |
@Digits (integer, fraction) | 정수, 소수 자릿수 검사 |
@Past | 과거 날짜인지 검사 |
@Future | 미래 날짜인지 검사 |
@Pattern(value) | 정규식 검사 |
제공하는 어노테이션 외에 복잡한 문자열 같은 경우에는 정규식을 많이 이용하거나
커스텀 어노테이션을 사용하기도 한다.
커스텀 어노테이션을 사용하면 복잡한 유효성 검사를 쉽게 할 수 있다.
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {EmailValidator.class})
public @interface Email {
String message() default "올바른 이메일 형식이 아닙니다.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
위와 같이 어노테이션을 만들고, 어노테이션에 대한 검사를 할 클래스를 만들어준다.
public class EmailValidator implements ConstraintValidator<Email, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
return value.matches("^[a-zA-Z0-9]+@[a-zA-Z0-9]+\\.[a-zA-Z0-9]+$");
}
}
위와 같이 어노테이션을 만들어 사용할 수 있다.
유효성 검사를 통과하지 못하면 에러 메시지를 보여줘야 한다.
@Data
public class UserDto {
@NotBlank
private String name;
@NotBlank
@Email
private String email;
@NotBlank
private String password;
}
위와 같이 DTO에 유효성 검사를 할 어노테이션을 추가하고, 컨트롤러에서 유효성 검사를 한다.
@PostMapping("/users")
public ResponseEntity<UserDto> createUser(@RequestBody @Valid UserDto userDto) {
return ResponseEntity.ok(userDto);
}
위와 같이 유효성 검사를 하고, 에러가 발생하면 MethodArgumentNotValidException
이 발생한다.
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setMessage("잘못된 요청입니다.");
errorResponse.setCode("E001");
errorResponse.setStatus(400);
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
List<ErrorResponse.Error> errors = fieldErrors.stream()
.map(error -> new ErrorResponse.Error(error.getField(), error.getDefaultMessage()))
.collect(Collectors.toList());
errorResponse.setErrors(errors);
return ResponseEntity.badRequest().body(errorResponse);
}
위와 같이 MethodArgumentNotValidException
을 처리해주면 에러 메시지를 보여줄 수 있다.
@Valid
어노테이션을 사용하면 객체에 있는 유효성 검사를 할 수 있다.
@PostMapping("/users")
public ResponseEntity<UserDto> createUser(@RequestBody @Valid UserDto userDto) {
return ResponseEntity.ok(userDto);
}
위와 같이 @Valid
어노테이션을 사용하면 객체에 있는 유효성 검사를 할 수 있다.
@Validated
어노테이션을 사용하면 객체에 있는 유효성 검사를 할 수 있다.
@PostMapping("/users")
public ResponseEntity<UserDto> createUser(@RequestBody @Validated UserDto userDto) {
return ResponseEntity.ok(userDto);
}
위와 같이 @Validated
어노테이션을 사용하면 객체에 있는 유효성 검사를 할 수 있다.
@Valid는 JSR-303의 기본 어노테이션을 사용하고, @Validated는 Spring의 어노테이션을 사용한다.
@Validated 는 @Valid의 내용을 포함하며 그룹핑을 지원한다.