📌 RestControllerAdvice란?
@RestControllerAdvice는 Spring에서 제공하는 어노테이션으로, 전역적으로 예외를 처리하기 위해 사용됩니다. 이는 @ControllerAdvice와 @ResponseBody를 결합한 형태로, 모든 컨트롤러에서 발생하는 예외를 JSON 형태로 응답하도록 설계되었습니다. 🌟
간단히 말하면:
- @ControllerAdvice + @ResponseBody의 조합입니다.
- 서버에서 발생한 예외를 전역적으로 감지하고, 그 결과를 JSON과 같은 형태로 클라이언트에게 반환할 때 사용합니다.
📌 @RestControllerAdvice의 특징
- 전역 예외 처리: 애플리케이션 전체에서 발생하는 예외를 한 곳에서 관리할 수 있습니다.
- REST API 전용: 반환값이 자동으로 JSON 또는 XML 형태로 변환됩니다. (별도의 @ResponseBody 어노테이션이 필요 없음)
- REST API 환경에서 주로 사용되며, 클라이언트가 API 호출 시 발생한 예외를 JSON 형태로 명확하게 전달받을 수 있습니다.
📌 주요 특징
- 🌍 전역 예외 처리: 특정 컨트롤러 또는 애플리케이션 전체에서 발생하는 예외를 한 곳에서 처리할 수 있습니다.
- 📜 JSON 응답 지원: @ResponseBody가 포함되어 있어 예외 처리 결과를 JSON 형태로 반환합니다.
- ⚙️ AOP 기반: 공통 관심사(cross-cutting concerns)를 분리하여 코드 중복을 줄이고 유지보수성을 높입니다.
📌 코드 해석
public class CommonException {
private final String message;
private final int statusCode;
private final String uri;
public CommonException(String message, int statusCode, String uri) {
this.message = message;
this.statusCode = statusCode;
this.uri = uri;
}
public String getMessage() {
return message;
}
public int getStatusCode() {
return statusCode;
}
public String getUri() {
return uri;
}
}
@RestControllerAdvice(basePackageClasses = {BlogController.class})
public class BlogAdvice {
@ExceptionHandler(BlogNotFoundException.class)
public ResponseEntity<CommonException> blogNotFoundExceptionHandler(
BlogNotFoundException blogNotFoundException,
HttpServletRequest request
){
CommonException commonException = new CommonException(
blogNotFoundException.getMessage(),
HttpStatus.NOT_FOUND.value(),
request.getRequestURI()
);
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(commonException);
}
@ExceptionHandler(AlreadyExistBlogFidException.class)
public ResponseEntity<CommonException> AlreadyExistBlogFidExceptionHandler(
AlreadyExistBlogFidException alreadyExistBlogFidException,
HttpRequest request
){
CommonException commonException = new CommonException(
alreadyExistBlogFidException.getMessage(),
HttpStatus.CONFLICT.value(),
request.getURI().toString()
);
return ResponseEntity
.status(HttpStatus.CONFLICT)
.body(commonException);
}
}
1️⃣ 클래스 정의
@RestControllerAdvice(basePackageClasses = {BlogController.class})
public class BlogAdvice {
- @RestControllerAdvice: 이 클래스는 전역적으로 예외를 처리하며, JSON 응답을 반환합니다.
- basePackageClasses: BlogController 클래스만 대상으로 설정하여 해당 컨트롤러에서 발생하는 예외를 처리합니다.
2️⃣ BlogNotFoundException 처리
- @ExceptionHandler(BlogNotFoundException.class): BlogNotFoundException이 발생했을 때 이 메서드가 호출됩니다.
- 매개변수 설명:
- BlogNotFoundException: 발생한 예외 객체.
- HttpServletRequest: 요청 정보를 가져오기 위해 사용됩니다 (예: 요청 URI).
- 응답 구성:
- 예외 메시지, 상태 코드(404), 요청 URI를 포함한 CommonException 객체를 생성.
- ResponseEntity.status(HttpStatus.NOT_FOUND).body(commonException)를 통해 상태 코드와 본문을 반환.
3️⃣ AlreadyExistBlogFidException 처리
- @ExceptionHandler(AlreadyExistBlogFidException.class): AlreadyExistBlogFidException이 발생했을 때 호출됩니다.
- 매개변수 설명:
- AlreadyExistBlogFidException: 발생한 예외 객체.
- HttpRequest: 요청 정보를 가져오기 위해 사용됩니다 (예: 요청 URI).
- 응답 구성:
- 예외 메시지, 상태 코드(409), 요청 URI를 포함한 CommonException 객체 생성.
- ResponseEntity.status(HttpStatus.CONFLICT).body(commonException)를 통해 상태 코드와 본문을 반환.
📌 RestControllerAdvice의 장점
- ✅ 일관성 있는 에러 응답: 모든 컨트롤러에서 동일한 형식의 에러 응답을 반환할 수 있습니다.
- 🌍 전역 관리: 개별 컨트롤러에 중복된 예외 처리 코드를 작성하지 않아도 됩니다.
- 📜 JSON 응답 자동화: 별도의 변환 작업 없이 JSON 형태로 에러 정보를 클라이언트에 전달합니다.
📌 사용 예시
✅ 1. 기본적인 사용법
@RestControllerAdvice
public class GlobalRestExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<Map<String, Object>> handleException(Exception e) {
Map<String, Object> response = new HashMap<>();
response.put("error", e.getMessage());
response.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
}
}
- 위 코드는 모든 타입의 예외(Exception)가 발생했을 때 JSON 형태로 에러 메시지와 상태 코드를 클라이언트에게 반환합니다.
✅ 예외가 발생했을 때 반환되는 JSON 형태
{
"error": "예외 메시지 내용",
"status": 500
}
✅ 설명
- "error": 예외 객체(Exception)의 메시지(e.getMessage())가 들어갑니다.
- "status": HTTP 상태 코드로, 여기서는 500 (Internal Server Error)를 의미합니다.
✅ 실제 예시
예를 들어, 서버에서 다음과 같은 예외가 발생했다고 가정해봅시다:
throw new RuntimeException("서버에서 에러가 발생했습니다.");
이 경우 클라이언트가 받게 되는 JSON 응답은 다음과 같습니다:
{
"error": "서버에서 에러가 발생했습니다.",
"status": 500
}
✅ 2. 특정 예외 처리 (예: 유효성 검증 실패)
@RestControllerAdvice
public class ValidationExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, Object>> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, Object> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage())
);
return ResponseEntity.badRequest().body(errors);
}
}
- 유효성 검증 실패 시 각 필드의 오류 메시지를 JSON 형태로 반환합니다.
✅ 유효성 검증 실패 시 반환되는 JSON 형태
{
"username": "사용자 이름은 필수입니다.",
"email": "올바른 이메일 형식을 입력해주세요."
}
✅ 설명
- JSON의 각 키(key)는 유효성 검증에 실패한 필드의 이름입니다.
- 각 값(value)은 해당 필드에 대한 유효성 검증 실패 메시지입니다.
✅ 실제 예시
예를 들어, 다음과 같은 DTO 클래스가 있다고 가정해봅시다:
public class UserRequest {
@NotBlank(message = "사용자 이름은 필수입니다.")
private String username;
@Email(message = "올바른 이메일 형식을 입력해주세요.")
private String email;
// getters, setters 생략
}
클라이언트가 잘못된 데이터를 전송한 경우:
{
"username": "",
"email": "invalid-email-format"
}
이 경우 클라이언트가 받게 되는 JSON 응답은 다음과 같습니다:
{
"username": "사용자 이름은 필수입니다.",
"email": "올바른 이메일 형식을 입력해주세요."
}
📌 @ControllerAdvice와의 차이점
| 특징 | @ControllerAdvice | @RestControllerAdvice |
| 반환 형식 | 주로 HTML 뷰 반환 | JSON/XML 데이터 반환 |
| 용도 | MVC 웹 애플리케이션 | REST API 전용 |
| 추가 어노테이션 필요 여부 | @ResponseBody 필요 (JSON 반환 시) | 자동으로 JSON/XML 변환 |
- 즉, REST API 환경에서는 일반적으로 @RestControllerAdvice를 사용하는 것이 더 편리합니다.
📌 결론
- @RestControllerAdvice는 REST API 환경에서 전역적인 예외 처리를 위해 사용됩니다.
- 서버에서 발생한 예외를 감지하고, 이를 JSON이나 XML 형태로 클라이언트에게 명확하게 전달할 수 있습니다.
- RESTful 서비스를 개발할 때 매우 유용한 어노테이션입니다.
'Spring > 10. rest-api' 카테고리의 다른 글
| Controller 와 FeignClient에서의 @PathVariable 역할 (0) | 2025.03.17 |
|---|---|
| FeignClient (0) | 2025.03.17 |
| ResponseEntity 작성 규칙 + build()가 붙는 경우 (0) | 2025.03.17 |
| ResponseEntity의 메서드들 (0) | 2025.03.16 |
| @PathVariable / @RequesteBody / @RequestParam (0) | 2025.03.16 |