웹 애플리케이션에서 클라이언트로부터 데이터를 받을 때, 값이 유효하지 않다면 서비스 로직이 실행되기 전에 차단하는 것이 안전하다.
Spring Boot에서는 @Valid 또는 @Validated 어노테이션을 활용해 손쉽게 입력값 검증을 수행할 수 있다.
하지만 유효성 검증에서 실패하면 MethodArgumentNotValidException 같은 예외가 발생하고, 기본적으로는 깔끔한 JSON 형태로 응답되지 않는다.
@Valid 유효성 검사와 @ExceptionHandler를 활용하여 사용자 친화적인 에러 메시지 응답을 구현하는 방법 ⬇️
@Valid와 유효성 검사 어노테이션
Spring Boot에서는 DTO 클래스에 다양한 검증 어노테이션을 붙여 입력값을 제한할 수 있다.
대표적으로 다음과 같은 어노테이션이 있다.
@NotNull | null 허용 안 함 | @NotNull(message = "값을 입력해주세요.") |
@Size | 문자열 길이 제한 | @Size(min = 3, max = 20) |
이메일 형식 검증 | @Email(message = "이메일 형식으로 입력해 주세요.") | |
@Pattern | 정규식 패턴 매칭 | @Pattern(regexp = "^[0-9]{4}$") |
예시 DTO:
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
public class UserRequest {
@NotNull(message = "이름은 필수 입력값입니다.")
@Size(min = 2, max = 20, message = "이름은 2~20자 사이여야 합니다.")
private String name;
@NotNull(message = "이메일은 필수 입력값입니다.")
@Email(message = "이메일 형식으로 입력해 주세요.")
private String email;
@NotNull(message = "비밀번호는 필수 입력값입니다.")
@Size(min = 8, message = "비밀번호는 최소 8자 이상이어야 합니다.")
private String password;
...
}
Controller에서 @Valid 사용
컨트롤러에서 @RequestBody와 함께 @Valid를 붙이면, 요청 바디를 매핑할 때 자동으로 유효성 검증이 수행된다.
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/users")
public class UserController {
@PostMapping
public ResponseEntity<String> createUser(@Valid @RequestBody UserRequest userRequest) {
return ResponseEntity.ok("회원가입 성공");
}
}
이 상태에서 유효성 검증을 통과하지 못하면 MethodArgumentNotValidException이 발생하게 된다.
@ExceptionHandler로 예외 처리하기
Spring Boot에서 전역 예외 처리를 위해 @ControllerAdvice와 @ExceptionHandler를 함께 사용한다.
아래 예시는 MethodArgumentNotValidException 예외를 잡아, 검증 실패한 필드와 메시지를 JSON 형태로 반환하는 방법이다.
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
for (FieldError error : ex.getBindingResult().getFieldErrors()) {
errors.put(error.getField(), error.getDefaultMessage());
}
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errors);
}
}
실행 예시
요청
POST /api/users
Content-Type: application/json
{
"name": "A",
"email": "invalid-email",
"password": "123"
}
응답
HTTP 상태 코드 400 Bad Request
{
"name": "이름은 2~20자 사이여야 합니다.",
"email": "이메일 형식으로 입력해 주세요.",
"password": "비밀번호는 최소 8자 이상이어야 합니다."
}
- @Valid와 Bean Validation 어노테이션을 사용하면 서버 단에서 강력하고 간단한 유효성 검사를 할 수 있다.
- 기본 예외 응답은 사용자 친화적이지 않을 수 있으므로, @RestControllerAdvice + @ExceptionHandler로 응답 포맷을 커스터마이징하는 것이 좋다.
- 이 방법을 사용하면 프론트엔드나 API 클라이언트가 에러를 명확히 파악하고 처리할 수 있다.
반응형
'IT > Spring' 카테고리의 다른 글
H2 인메모리 DB의 동작 원리 (2) | 2025.08.12 |
---|---|
Spring Data JPA 페이지네이션(Pagination) 처리 (1) | 2025.07.30 |
JPA에서 deleteAll() vs deleteAllInBatch()의 차이와 주의할 점 (0) | 2025.07.19 |
스프링 어노테이션 (0) | 2025.07.15 |
HikariCP (1) | 2025.07.12 |