* 참고
일반 예외로 선언할 경우 Exception을 상속받아 구현 (컴파일러가 체크)
실행 예외로 선언할 경우에는 RuntimeException을 상속받아 구현
1. CustomException을 사용하는 이유
상세한 예외 정보를 제공, 이름으로도 정보 전달이 가능
Enum과 함께 사용하여 예외에 대한 응집도를 높일 수 있음
@ControllerAdvice, @RestControllerAdvice에서 해당 Custom Exception에 대한 자세한 후처리가 가능 (전역적인 예외 처리)
2. 총 4가지의 클래스
1. Exception이 발생하였을때 알려준 Status 상태와 메시지를 담은 enum 클래스
package org.example.exception;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
@Getter
@RequiredArgsConstructor
public enum CustomErrorCode {
//== 400 ==//
NOT_SUPPORTED_HTTP_METHOD(HttpStatus.BAD_REQUEST, "지원하지 않는 Http Method 방식입니다."),
NOT_VALID_METHOD_ARGUMENT(HttpStatus.BAD_REQUEST, "유효하지 않은 Request Body 혹은 Argument입니다."),
BAD_REQUEST(HttpStatus.BAD_REQUEST, "ᕕ( ᐛ )ᕗ 잘못된 요청입니다."),
NOT_FOUND(HttpStatus.NOT_FOUND, "ᕕ( ᐛ )ᕗ 리소스를 찾을 수 없습니다."),
//== 500 ==//
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 내부 오류가 발생했습니다.");
private final HttpStatus httpStatus;
private final String message;
}
2. Dto 역할을 하고있는 CustomErrorResponse
package org.example.exception;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
public record ResponseMessage <T> (HttpStatus status, String message, T data) {
public static ResponseEntity<ResponseMessage> error(CustomException e) {
return ResponseEntity
.status(e.getCustomErrorCode().getHttpStatus())
.body(new ResponseMessage<>(
e.getCustomErrorCode().getHttpStatus(),
e.getCustomErrorCode().getMessage(),
null
));
}
public static <T> ResponseEntity<ResponseMessage> success(HttpStatus status, String message, T data) {
return ResponseEntity
.status(status)
.body(new ResponseMessage<>(
status,
message,
data
));
}
}
3. RuntimeException을 상속받아 커스텀화 해준 클래스
package org.example.exception;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public class CustomException extends RuntimeException {
private final CustomErrorCode customErrorCode;
}
4. 커스텀화 한 클래스 및 다른 Exception들의 Handler 클래스
package org.example.exception;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@Slf4j
@RestControllerAdvice // CustomException 발생 시, 프런트로 보낼 ErrorDTO 를 생성하고, ErrorDTO 를 전달하는 handler
public class CustomExceptionHandler {
@ExceptionHandler(value = CustomException.class)
public ResponseEntity<ResponseMessage> handleCustomException(CustomException e) {
// 에러에 대한 후처리
log.error("[handleCustomException] {} : {}", e.getCustomErrorCode().name(), e.getCustomErrorCode().getMessage());
return ResponseMessage.error(e);
}
// HttpRequestMethodNotSupportedException 처리
@ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
public ResponseEntity<ResponseMessage> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e) {
log.error("[handleHttpRequestMethodNotSupported] {}", e.getMessage());
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(new ResponseMessage<>(
HttpStatus.BAD_REQUEST,
CustomErrorCode.NOT_SUPPORTED_HTTP_METHOD.getMessage(),
null
));
}
// MethodArgumentNotValidException 처리
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public ResponseEntity<ResponseMessage> handleMethodArgumentNotValid(MethodArgumentNotValidException e) {
log.error("[handleMethodArgumentNotValid] {}", e.getMessage());
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(new ResponseMessage<>(
HttpStatus.BAD_REQUEST,
CustomErrorCode.NOT_VALID_METHOD_ARGUMENT.getMessage(),
null
));
}
// 전역 예외 처리 (기타)
@ExceptionHandler(Exception.class)
public ResponseEntity<ResponseMessage> handleGeneralException(Exception e) {
log.error("[handleGeneralException] {}", e.getMessage(), e);
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ResponseMessage<>(
HttpStatus.INTERNAL_SERVER_ERROR,
CustomErrorCode.INTERNAL_SERVER_ERROR.getMessage(),
null
));
}
}
참고 :
'Spring' 카테고리의 다른 글
필터와 인터셉터 (0) | 2025.02.07 |
---|---|
ArgumentResolver (0) | 2025.01.19 |
디버깅 모드 (0) | 2025.01.19 |
FeignClient (1) | 2025.01.19 |
멀티 모듈 (Multi-Module) (0) | 2025.01.17 |