ControllerAdvice 사용 이유
1) 하나의 클래스로 모든 컨트롤러에 대해 전역적으로 예외 처리 가능
2) 직접 정의한 에러 응답을 일관성있게 클라이언트에게 내려줄 수 있음
3) 별도의 try-catch문이 없어 코드의 가독성이 높아짐
ControllerAdvice 사용시 주의사항
- 한 프로젝트당 하나의 ControllerAdvice만 관리하는 것이 좋음
- 만약 여러 ControllerAdvice가 필요하다면 basePackages나 annotations 등을 지정해야 함.
- 직접 구현한 Exception 클래스들은 한 공간에서 관리
/*
공통 ErrorCode Interface
*/
public interface ErrorCode {
String name();
HttpStatus getHttpStatus();
String getMessage();
}
/*
ErrorCode 구현체로 공통 Error Enum
*/
@Getter
@RequiredArgsConstructor
public enum CommonErrorCode implements ErrorCode{
INVALID_REQUEST(HttpStatus.BAD_REQUEST, "잘못된 요청입니다."),
SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버오류 입니다."),
NOT_FOUND_ERROR(HttpStatus.NOT_FOUND, "찾을 수 없는 항목입니다.")
;
private final HttpStatus httpStatus;
private final String message;
}
/*
Custom Exception
*/
@Getter
@RequiredArgsConstructor
public class RestApiException extends RuntimeException{
private final ErrorCode errorCode;
}
/*
공통 Error 응답 형태
*/
@Getter
@Builder
public class ErrorResponse {
private String name;
private String message;
}
/*
전역 예외 처리
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RestApiException.class)
public ResponseEntity<ErrorResponse> handleCustomException(RestApiException e) {
ErrorCode errorCode = e.getErrorCode();
return ResponseEntity.status(errorCode.getHttpStatus())
.body(makeErrorResponse(errorCode));
}
@ExceptionHandler({Exception.class})
public ResponseEntity<ErrorResponse> handleAllExcpetion(Exception ex) {
log.warn("handleAllException", ex);
ErrorCode errorCode =CommonErrorCode.SERVER_ERROR;
return ResponseEntity.status(errorCode.getHttpStatus())
.body(makeErrorResponse(errorCode));
}
public ErrorResponse makeErrorResponse(ErrorCode e) {
return ErrorResponse.builder()
.name(e.name())
.message(e.getMessage())
.build();
}
}
참고 자료를 바탕으로 작성한 글로써 전역 예외처리 방법에 대해 배우게 되었다. 무분별한 예외 처리가 아닌 공통적으로 예외를 작성할 수 있다는 점과 예외에 대한 응답이 일관성을 가질 수 있다는 점에서 팀 내부에서 예외에 대한 기준점과 명확한 내용을 바탕으로 사용한다면 유용하게 처리가 가능할 것 같다.