1. HTTP 상태 코드 (자주 쓰이는 것)
✅ 2xx (성공)
- 200 OK : 조회 / 수정 성공, 일반적인 성공 응답
- 201 Created : 리소스 생성 성공 (보통 Location 헤더 포함)
- 204 No Content : 성공했지만 응답 바디 없음 (삭제 성공 등)
❌ 4xx (클라이언트 요청 문제)
- 400 Bad Request : 요청 / 값 형식이 잘못됨(검증 실패, 타입 변환 실패, JSON 파싱 실패 등)
- 401 Unauthorized : 인증 실패 (로그인, 토큰 없음, 만료 등)
- 403 Forbidden : 인증은 됐지만 권한 없음 (ROLE 부족)
- 404 Not Found : 리소스 없음 (id로 조회했는데 없음)
- 405 Method Not Allowed : GET만 되는데 POST로 호출 시
- 409 Conflict : 중복/충돌 (유니크 제약 위반, "이미 존재 시")
- 415 Unsupported Media Type : Content-Type이 서버에서 지원하지 않음 (JSON 필요한데 다른 타입인 경우)
❌ 5xx (서버 문제)
- 500 Internal Server Error : 서버 내부 예외 (예상 못한 오류 발생)
→ Exception.class 로 마지막 안전망을 통해 500 처리 및 로그 표기
2. 자주 만나는 예외
입력/검증 예외
- MethodArgumentNotValidException
- @Valid DTO 검증 실패 → 400
- HttpMessageNotReadableException
- JSON 파싱 실패 → 400
- MethodArgumentTypeMismatchException
- 파라미터 타입 변환 실패 → 400
- MissingServletRequestParameterException
- 필수 파라미터 누락 → 400
- IllegalArgumentException
- 요청 값이 유효하지 않음 (범위/형식/조건 위반 등) → 400
인증/권한 (Security)
- AuthenticationException
- 인증 실패 → 401
- AccessDeniedException
- 권한 없음 → 403
조회 / 리소스 없음
- NoSuchElementException / EntityNotFoundException
- 조회 실패 → 404
비즈니스 상태 충돌 / 처리 불가
- IllegalStateException
- 현재 상태 때문에 처리 불가 (중복 생성, 상태 충돌) → 409
DB 무결성 / 중복
- DataIntegrityViolationException
- UNIQUE / FOREIGN KEY 위반 등 → 409 또는 400
안전망
- Exception
- 예상치 못한 예외 (안전망) → 500
3. 🌱 Spring 에서 예외 처리 방식
1. try - catch 를 통한 직접 처리
@GetMapping("/member/{id}")
public ResponseEntity<?> getMember(@PathVariable Long id){
try{
return ResponseEntity.ok(service.find(id));
} catch (NoSuchElementException e) {
return ResponseEntity.status(HttpStatus.Not_Found).body("not found");
}
}
- 장점
- 빠르게 구현 가능
- 단점
- 컨트롤러마다 코드 반복되고, 유지보수가 힘듦
2. @ResponseStatus 로 예외에 상태 코드 붙이기
@ResponseStatus(HttpStatus.NOT_FOUND)
public class MemberNotFoundException extends RuntimeException{
public MemberNotFoundException(String message){
super(message);
}
}
- 장점
- 간단함, 예외 클래스만 만들면 끝
- 단점
- 응답 바디 형식 (에러 DTO)을 통일하기 어렵고, 상황별 메시지 / 필드 관리가
불편할 수 있음
- 응답 바디 형식 (에러 DTO)을 통일하기 어렵고, 상황별 메시지 / 필드 관리가
3. @RestControllerAdvice + @ExceptionHandler ⭐️❗️
✅ 전역 (Global)에서 예외를 잡아 응답 형식과 상태 코드 통일
✅ 실무에서 가장 많이 쓰이는 방식 !
@RestControllerAdvice
public class GlobalExceptionHandler{
@ExceptionHandler(NoSuchElementException.class)
public ResponseEntity<ErrorResponseDTO> handleNoSuchElement(NoSuchElementException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponseDTO("NOT_FOUND", e.getMessage()));
}
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ErrorResponseDTO> handleBadRequest(IllegalArgumentException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponseDTO("BAD_REQUEST", e.getMessage()));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponseDTO> handleException(Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponseDTO("INTERNAL_ERROR", "서버 오류가 발생했습니다."));
}
}
- 장점
- 컨트롤러 코드 깔끔, 에러 응답 규격 통일, 확장 가능성 ↑
- 단점
- 예외 매핑 규칙을 잘 설계 필요
4. 스프링 기본 에러 처리 (BasicErrorController)
예외 처리를 따로 안 하면 스프링이 /error 로 라우팅 해서 기본 JSON 반환
- 장점
- 최소 설정
- 단점
- 서비스 규격 (에러 DTO)으로 맞추기 어려움 → 실무에서는 보통 커스터마이징
혹은 3) 전역 예외 처리로 통일
- 서비스 규격 (에러 DTO)으로 맞추기 어려움 → 실무에서는 보통 커스터마이징
'Spring' 카테고리의 다른 글
| [Spring] Kafka 기반 예매 시스템 성능 개선기: MySQL 병목, Redis 재고 차감, 그리고 정합성 트레이드오프 (0) | 2026.05.17 |
|---|---|
| [Spring] CaffeineCache TTL 설정 오류로 인한 NPE 발생 사례 (0) | 2026.04.29 |
| [Spring] 출금 및 장부 시스템 구현 (2) | 2025.12.08 |
| [Spring] 충전 기능 구현 with. TossPayments (0) | 2025.11.29 |
| [Spring] 웹소켓(STOMP) 을 이용한 채팅 구현 (0) | 2025.09.04 |