아래는 개발 블로그에 바로 올려도 될 퀄리티로 정리한 @RestControllerAdvice 완전 이해 가이드야. Spring Boot + Kotlin/Java 개발자가 꼭 알아야 할 핵심 개념들만, 실무 스타일로 정리했어.
⸻
🚀 Spring Boot에서 @RestControllerAdvice 완벽 가이드
— “컨트롤러 예외 처리의 정석”
웹 애플리케이션을 만들다 보면 컨트롤러마다 이런 코드가 반복된다.
try { ... } catch (Exception e) { jsonData.put("result", "fail"); }
문제는? • 모든 API마다 try-catch 반복 → 지저분함 • 예외가 각각 다르게 처리됨 → 일관성 없음 • 에러 메시지 포맷 관리 불가 → 클라이언트 혼란 • 유지보수 난이도 ↑
Spring Boot에서는 이런 문제를 해결하기 위해 **전역 컨트롤러 예외 처리기(Global Exception Handler)**를 제공한다. 그 핵심이 바로 @RestControllerAdvice 이다.
⸻
1️⃣ @RestControllerAdvice란 무엇인가?
한마디로,
컨트롤러에서 발생하는 모든 예외를 한 곳에서 처리하는 전역 예외 처리기
다른 말로 하면… • 컨트롤러 예외를 하나의 클래스에서 처리 • API 응답 포맷을 통일 • 중복 try-catch 제거 • 공통 로깅·추가 작업 가능
✔ @ControllerAdvice + @ResponseBody 의 조합
@RestControllerAdvice는 아래 두 어노테이션을 합쳐 놓은 것과 같다.
어노테이션 의미 @ControllerAdvice 전역적으로(모든 컨트롤러에) 적용 @ResponseBody 반환 객체를 JSON으로 응답
그래서 API 개발에서는 사실상 필수라고 보면 된다.
⸻
2️⃣ 예외 처리의 기본 구조
예외 핸들러는 아래처럼 만든다.
@RestControllerAdvice class GlobalExceptionHandler {
@ExceptionHandler(Exception::class)
fun handleException(e: Exception): ApiResponse<Unit> {
return ApiResponse(
success = false,
message = "시스템 오류가 발생했습니다.",
errorCode = "INTERNAL_ERROR"
)
}
}
⸻
3️⃣ 동작 방식 (Internals)
Spring MVC는 컨트롤러에서 예외가 발생하면 다음 순서로 처리한다: 1. 컨트롤러 내부에서 try-catch로 처리? → 여기서 끝. 2. 처리되지 않은 예외 발생 → DispatcherServlet이 @ExceptionHandler를 탐색한다. 3. 가장 맞는 타입의 예외 핸들러 메서드를 호출한다.
즉, 아래처럼 다양한 예외를 구분할 수도 있다.
@ExceptionHandler(IllegalArgumentException::class)
fun handleBadRequest(e: IllegalArgumentException): ApiResponse
@ExceptionHandler(NoSuchElementException::class)
fun handleNotFound(e: NoSuchElementException): ApiResponse
⸻
4️⃣ 실무에서 가장 많이 쓰는 예외 유형별 처리
✔ 잘못된 요청 (400)
@ExceptionHandler(IllegalArgumentException::class) fun badRequest(e: IllegalArgumentException) = ApiResponse(false, message = e.message ?: "잘못된 요청입니다.")
✔ 찾을 수 없음 (404)
@ExceptionHandler(NoSuchElementException::class) fun notFound(e: NoSuchElementException) = ApiResponse(false, message = "데이터를 찾을 수 없습니다.")
✔ 서버 오류 (500)
@ExceptionHandler(Exception::class) fun internal(e: Exception) = ApiResponse(false, message = "시스템 오류가 발생했습니다.")
이렇게 해두면 컨트롤러는 예외를 던지기만 해도 OK:
if (list.isEmpty()) throw NoSuchElementException()
⸻
5️⃣ 실제 실무 스타일 예제 (Response Wrapper 포함)
ApiResponse라는 공통 응답 DTO를 만들어서 통합 관리한다.
data class ApiResponse
그리고…
@RestControllerAdvice class GlobalExceptionHandler {
@ExceptionHandler(Exception::class)
fun handle(e: Exception): ResponseEntity<ApiResponse<Unit>> {
// 로그
e.printStackTrace()
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(
ApiResponse(
success = false,
message = "시스템 오류가 발생했습니다.",
errorCode = "INTERNAL_ERROR"
)
)
}
}
⸻
6️⃣ 기존 코드가 어떻게 깔끔해지는지 비교해보기
🔥 Before (try-catch 반복)
@RequestMapping(...) public Map<String, Object> readSomething() { Map<String,Object> json = new HashMap<>(); try { json.put("data", service.read()); json.put("result", "ok"); } catch (Exception e) { e.printStackTrace(); json.put("message", "오류"); json.put("result", "fail"); } return json; }
⸻
🌟 After (@RestControllerAdvice 적용)
@GetMapping("/something")
fun readSomething(): ApiResponse
실수로 예외가 발생해도: • try-catch 필요 없음 • 응답 포맷 자동 정리 • 로그도 자동 • 일관성 유지
⸻
7️⃣ 흔히 쓰는 고급 패턴들
✔ 비즈니스 예외 직접 생성하기
class BizException( val code: String, override val message: String ) : RuntimeException(message)
핸들러:
@ExceptionHandler(BizException::class) fun handleBizException(e: BizException) = ApiResponse(false, message = e.message, errorCode = e.code)
컨트롤러에서는 그냥 던지면 됨:
if (!valid) throw BizException("VALID_FAIL", "유효하지 않은 값입니다.")
⸻
8️⃣ 왜 실무에서 무조건 쓰는가?
장점 설명 중복 제거 모든 try-catch 제거 유지보수성 에러 정책 변경이 매우 쉬움 일관성 모든 API 응답 패턴을 통일 확장성 예외 종류별 처리 가능 보안 내부 에러 스택을 클라이언트에 노출하지 않음
특히 MES/ERP 같이 화면이 수십~수백개인 시스템에서는 한 줄당 1초씩만 절약되어도 몇 시간 절약됨.
⸻
9️⃣ 실제 현업에서 사용하는 패턴 조합 • @RestControllerAdvice • @ExceptionHandler • 공통 Response DTO (ApiResponse) • Custom BizException • ValidationException 처리 • Authentication/Authorization Exception 처리
이 세트를 템플릿화하면 새로운 프로젝트 시작할 때 바닥공사 80%는 이미 끝난 상태가 된다.
⸻
🔟 마무리
@RestControllerAdvice는 **“Spring Boot API 개발의 필수 인프라”**다.
이걸 적절히 설계해두면: • 컨트롤러는 “정상 로직”만 작성 • 예외는 자동 관리 • 응답도 자동 통일 • 유지보수 시간 절약 • 코드 가독성 상승
결국 개발자가 본질적인 업무 로직에 집중할 수 있게 해주는 핵심 기술이다.
⸻
원하면: 🛠 Kotlin + Spring Boot 기반으로 “전역 예외처리 모듈 세트(파일 3개)”를 완성 형태로 생성해서 제공해줄게. Junha MES 프로젝트 형태에 맞추어 바로 사용할 수 있는 수준으로.