코딩/sparta TIL

TIL 27 : Spring 예외처리 방법

americanoallday 2025. 3. 26. 11:48
어노테이션 역할 사용처
@Valid 유효성 검사 시작 트리거 @RequestBody, @ModelAttribute 등 DTO 매개변수
@Validated @Valid와 같지만 그룹 지정 기능 추가 마찬가지로 Controller 파라미터
@ExceptionHandler 특정 예외 처리 메서드 Controller 클래스 안 or @ControllerAdvice 클래스 안
@ControllerAdvice 전역 예외 처리 담당 클래스 전체 Controller 대상으로 예외 핸들링

 

✅ 1. @Valid vs @Validated

데이터를 검증하기 위한 어노테이션

이를 활성화 하기 위해서는 아래 의존성을 추가 해야 합니다.

// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation
implementation 'org.springframework.boot:spring-boot-starter-validation:3.3.5'

참고 사이트 : https://doubleyoo.tistory.com/48

 

[Spring] @Valid와 @Validated를 이용한 유효성 검증

참고: @Valid와 @Validated를 이용한 유효성 검증의 동작 원리 및 사용법 예시 Validation 올바르지 않은 데이터를 걸러내고, 보안을 유지하기 위해 데이터 검증은 여러 계층에 걸쳐서 적용된다. 클라이

doubleyoo.tistory.com

 

 

✅ @Valid (javax.validation)

DTO에 붙인 제약 조건들을 검사하게 함

일반적으로 단순한 필드 검증에 자주 사용

발생 예외 : MethodArgumentNotValidException

 적용 계층

- 기본 : Controller

- 별도 설정시 : Service, Bean 등 사용 가능

@RestController
public class UserController {
  @PostMapping("/user")
  public ResponseEntity<String> createUser(@RequestBody @Valid UserDto userDto){
        return ResponseEntity.ok("User is valid!");
  }
}

@Getter
public class UserDto {
    private Long id;
    @Min(20)
    private Long age;

    @Override
    public String toString() {
        return "UserDto{id=" + id + ", age=" + age + '}';
    }
}

@Valid가 붙은 DTO에서 유효성 오류 발생 시 → 예외 발생!

 

✅ @Validated (Spring 전용)

@Valid보다 조금 더 유연하고 확장 가능

특히 그룹 검사(grouping) 할 때는 @Validated를 써야 함

 발생 예외 : ConstraintViolationException

 적용 계층

- Controller + 다른 계층

@Validated
@RestController
public class ValidatedController {
    @PostMapping("/test-validated/number")
    public String testValid(@Min(10) Integer number, @RequestBody @Valid UserDto userDto) {
        return number + " : " + userDto.toString();
    }
}

@Getter
public class UserDto {
    private Long id;
    @Min(20)
    private Long age;

    @Override
    public String toString() {
        return "UserDto{id=" + id + ", age=" + age + '}';
    }
}

 

대부분 상황에선 @Valid만 써도 충분함

 

✅ 2. 필드 검증 어노테이션 (자주 쓰는 유효성 검사들)

어노테이션 설명
@NotNull null ❌ 허용 안 됨
@NotBlank 공백 ❌ 허용 안 됨 (문자열 전용)
@Size(min=1, max=50) 문자열/리스트의 길이 제한
@Min(1) / @Max(100) 숫자의 최소/최대 범위
@Positive 양수만 허용 (0 ❌)
@PositiveOrZero 양수 또는 0
@Email 이메일 형식 체크

참고 사이트 : https://better-tomorrow-than-today.tistory.com/98

 

@NonNull, @Nonnull, @NotNull, @NotEmpty, @NotBlank 비교

1. 정리하게된 배경초기 도메인 필드의 유효성을 검증하고자, 아래와 같이 @NonNull을 이용해서 구현했다. 초기 프로젝트 환경에서 validation 의존성이 추가되지 않아서, Spring 에서 제공되는 @NonNull

better-tomorrow-than-today.tistory.com

JSON 문법 검사 참고 사이트 : https://jsonformatter.curiousconcept.com/

 

🌼 예시 DTO

@Getter
public class ScheduleRequestDto {

    @NotBlank(message = "제목을 입력해주세요.")
    @Size(max = 100)
    private String title;

    @NotBlank(message = "내용을 입력해주세요.")
    private String content;

    @NotBlank(message = "이름은 필수입니다.")
    private String name;

    @NotBlank(message = "비밀번호는 필수입니다.")
    private String pw;

    @Email(message = "이메일 형식을 지켜주세요.")
    private String email;
}

 

✅ 3. 예외 처리 어노테이션

https://tecoble.techcourse.co.kr/post/2023-05-03-ExceptionHandler-ControllerAdvice/

 

ExceptionHandler와 ControllerAdvice를 알아보자

콘솔 애플리케이션을 구현할 때, 우리는 예외를 핸들링하기 위해 try / catch…

tecoble.techcourse.co.kr

 

✅ @ExceptionHandler

특정 예외가 발생했을 때 실행할 메서드를 지정해주는 어노테이션

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<String> handleValidationError(MethodArgumentNotValidException e) {
    return ResponseEntity.badRequest().body("유효성 검증 실패!");
}

 

✅ @ControllerAdvice

전역 예외 처리 클래스에 붙이는 어노테이션

모든 컨트롤러에서 발생한 예외를 한 곳에서 처리할 수 있음!

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<String> handleValidationError(MethodArgumentNotValidException e) {
        return ResponseEntity.badRequest().body("유효성 검사 실패! 💥");
    }
}

 

여기서 @ExceptionHandler메서드 단위

@ControllerAdvice클래스 단위

→ 이렇게 붙이면, 전역에서 예외를 한 곳에서 처리 가능

 

🧠 흐름을 이미지처럼 정리하면:

[Client 요청]
    ↓
@PostMapping 컨트롤러 메서드
    ↓
@RequestBody + @Valid 붙은 DTO
    ↓
Spring이 유효성 검사 수행
    ↓
  ✔️ 성공 → 로직 실행
  ❌ 실패 → @ControllerAdvice + @ExceptionHandler로 이동!