@ControllerAdvice와 @RestControllerAdvice의 차이점은 무엇인가요?

발행: (2025년 12월 23일 오후 12:17 GMT+9)
8 min read
원문: Dev.to

Source: Dev.to

realNameHidden

Spring Boot에서 @ControllerAdvice@RestControllerAdvice의 차이를 명확한 설명과 엔드‑투‑엔드 Java 예제로 배워보세요.

소개

Spring Boot를 사용하여 두 개의 애플리케이션을 만든다고 상상해 보세요.

  • 전통적인 웹 애플리케이션 – 브라우저에 HTML 페이지를 표시합니다.
  • REST API – 모바일 앱이나 React와 같은 프런트엔드 프레임워크에서 사용됩니다.

이제 뭔가 잘못되었다고 가정해 보세요—예를 들어 사용자를 찾을 수 없거나 잘못된 요청이 전송된 경우.

모든 컨트롤러 내부에서 오류를 처리하고 싶으신가요? 물론 아니죠.

Spring은 @ControllerAdvice@RestControllerAdvice를 사용하여 오류를 전역적으로 처리하는 깔끔한 방법을 제공합니다.

초보자들이 자주 묻는 질문:

  • 이 두 애노테이션은 동일한가요?
  • 언제 어떤 것을 사용해야 하나요?
  • REST API가 왜 다르게 동작하나요?

이 블로그에서는 명확한 개념과 엔드‑투‑엔드 실전 예제를 통해 @ControllerAdvice@RestControllerAdvice 차이점을 설명하고, 실제 Spring Boot 프로젝트에서 자신 있게 사용할 수 있도록 도와드립니다.

핵심 개념

@ControllerAdvice란?

@ControllerAdvice컨트롤러 전역에서 예외를 처리하기 위해 사용됩니다. 애플리케이션의 중앙 오류 처리기라고 생각하면 됩니다.

쉽게 이해하는 방법
각 컨트롤러가 개별적으로 오류를 처리하는 대신, 하나의 관리자가 모든 컨트롤러의 오류를 처리합니다.

핵심 포인트

  • @Controller와 함께 작동합니다 (MVC 애플리케이션)
  • 일반적으로 HTML 뷰 또는 ModelAndView를 반환합니다
  • JSON을 반환하려면 @ResponseBody가 필요합니다

사용 사례

  • 웹 애플리케이션
  • 서버‑사이드 렌더링 페이지 (Thymeleaf, JSP)
  • 커스텀 오류 페이지

@RestControllerAdvice란?

@RestControllerAdviceREST API에 특화되어 설계되었습니다. 기술적으로는 다음과 같습니다:

@ControllerAdvice + @ResponseBody

쉽게 이해하는 방법
오류 페이지를 반환하는 대신 구조화된 JSON 데이터를 반환합니다.

핵심 포인트

  • @RestController와 가장 잘 어울립니다
  • 응답을 자동으로 JSON으로 변환합니다
  • 마이크로서비스와 API에 이상적입니다

사용 사례

  • REST API
  • 모바일 또는 프론트엔드 기반 애플리케이션
  • 마이크로서비스 아키텍처

한눈에 보는 주요 차이점

특징@ControllerAdvice@RestControllerAdvice
애플리케이션 유형MVC / 웹 애플리케이션REST API
기본 응답HTML / 뷰JSON
@ResponseBody 필요 여부아니오
가장 적합한 대상UI 기반 애플리케이션API 및 마이크로서비스

Source:

End‑to‑End 코드 예제 (Java 21)

아래는 전체 작동 예제로, 각 어노테이션이 실제 시나리오에서 어떻게 사용되는지 보여줍니다.

예제 1: @ControllerAdvice를 사용한 End‑to‑End MVC 흐름

단계 1 – 사용자 정의 예외

public class PageNotFoundException extends RuntimeException {
    public PageNotFoundException(String message) {
        super(message);
    }
}

단계 2 – MVC 컨트롤러

@Controller
@RequestMapping("/pages")
public class PageController {

    @GetMapping("/{id}")
    public String getPage(@PathVariable int id) {
        if (id != 1) {
            throw new PageNotFoundException("Page not found with id: " + id);
        }
        return "home"; // returns an HTML page
    }
}

단계 3 – @ControllerAdvice를 사용한 전역 예외 처리기

@ControllerAdvice
public class GlobalMvcExceptionHandler {

    @ExceptionHandler(PageNotFoundException.class)
    public String handlePageNotFound(PageNotFoundException ex, Model model) {
        model.addAttribute("errorMessage", ex.getMessage());
        return "error"; // resolves to error.html
    }
}

결과: 브라우저가 HTML 오류 페이지를 받게 됩니다 – 컨트롤러 코드는 깔끔하게 유지하면서 중앙집중식 오류 처리를 수행합니다.

예제 2: @RestControllerAdvice를 사용한 End‑to‑End REST API 흐름

단계 1 – 사용자 정의 예외

public class ResourceNotFoundException extends RuntimeException {
    public ResourceNotFoundException(String message) {
        super(message);
    }
}

단계 2 – 오류 응답 모델

import java.time.LocalDateTime;

public record ErrorResponse(
        int status,
        String message,
        LocalDateTime timestamp
) {}

단계 3 – REST 컨트롤러

@RestController
@RequestMapping("/users")
public class UserController {

    @GetMapping("/{id}")
    public String getUser(@PathVariable Long id) {
        if (!id.equals(1L)) {
            throw new ResourceNotFoundException("User not found with id: " + id);
        }
        return "User found";
    }
}

단계 4 – @RestControllerAdvice를 사용한 전역 예외 처리기

@RestControllerAdvice
public class GlobalRestExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity handleResourceNotFound(
            ResourceNotFoundException ex) {

        ErrorResponse response = new ErrorResponse(
                HttpStatus.NOT_FOUND.value(),
                ex.getMessage(),
                LocalDateTime.now()
        );

        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
    }
}

결과 (JSON 응답):

{
  "status": 404,
  "message": "User not found with id: 2",
  "timestamp": "2025-01-10T12:30:45"
}

모범 사례

  • REST API에는 @RestControllerAdvice 사용 – 자동 직렬화(예: JSON)를 보장하고 @ResponseBody 누락을 방지합니다.
  • MVC 애플리케이션에는 @ControllerAdvice만 사용 – 뷰나 템플릿을 반환해야 할 때 이상적입니다.
  • 일관된 오류 응답 구조를 생성 – 프론트엔드 팀과 API 사용자가 오류를 일관되게 처리할 수 있도록 돕습니다.
  • 올바른 HTTP 상태 코드를 매핑 – 각 오류 상황에 맞게 400, 404, 401, 500 등을 적절히 사용합니다.
  • 일반 Exception 처리보다 먼저 구체적인 예외를 처리Exception.class에 fallback하기 전에 항상 특정 예외를 먼저 처리합니다.

Common Mistakes to Avoid

  • @ResponseBody 없이 REST API에서 @ControllerAdvice 사용
  • ❌ REST API에서 HTML 오류 페이지 반환
  • ❌ 예외를 개별 컨트롤러에서 처리하고 중앙에서 관리하지 않음
  • ❌ API 응답에 스택 트레이스나 내부 세부 정보 노출

결론

@ControllerAdvice@RestControllerAdvice의 차이는 애플리케이션이 오류를 전달하는 방식에 있습니다:

  • **@ControllerAdvice**는 HTML을 반환하는 전통적인 웹 애플리케이션에 사용합니다.
  • **@RestControllerAdvice**는 JSON(또는 기타 본문 기반 포맷)을 반환하는 REST API에 사용합니다.

두 어노테이션 모두 중앙 집중식이며 깔끔하고 확장 가능한 예외 처리를 제공합니다. 이 차이를 이해하면 실제 프로젝트든 면접이든 Spring Boot 애플리케이션을 더 쉽게 유지 보수하고 보다 전문적으로 만들 수 있습니다.

Back to Blog

관련 글

더 보기 »

분리를 분리하자

소개 2025년 말 며칠 동안, 우리 팀 리더는 하루를 추가로 쉬면서 중요한 회의를 놓쳤습니다. 최근 구조조정 이후, 한 동료가 떠났습니다.