반응형

목차

1. 개발환경

2. Global Exception은 무엇일까?

3. Global Exception를 사용하는 이유

4. @RestControllerAdvice?

5. @RestControllerAdvice의 주요 기능

6. ErrorResponse 코드

7. RestApiException 코드

8. ErrorCode 코드

9. GlobalExceptionHandler 코드

 

 

 

1. 개발환경

Java 17

Spring Boot 3.1.8

Gradle 8.5

 

 

2. Global Exception은 무엇일까?

Spring Boot 기반의 Restful API에서 예외처리의 유지보수성과 확장성을 향상하며, 명확한 에러 메시지를 제공하도록 도와준다. 에러코드와 메시지를 관리하며 GlobalExceptionHandler를 통해 이러한 예외들을 중앙에서 처리하도록 해준다.

 

 

 

3. Global Exception를 사용하는 이유

1 코드 중복 감소

동일한 예외를 반복해서 처리하는 것은 비효율적이다. 전역 예외를 사용하면 모든 컨트롤러에서 발생하는 공통 예외들을 한 곳에서 처리할 수 있으므로, 코드의 중복을 줄이고 유지보수가 용이해진다

 

2 일관된 에러 응답 형식

일관된 형식의 에러 응답을 제공하면 클라이언트가 더 쉽게 이해하고 처리할 수 있다.

 

3 유지보수성 향상

 애플리케이션의 규모가 커지면서 발생할 수 있는 예외의 종류와 복잡성이 증가한다. 전역 예외 처리를 통해 예외 처리 로직을 한곳에 집중함으로써, 향후 발생할 수 있는 변경사항이나 예외 처리 로직의 개선이 필요할 때, 이를 더 쉽게 관리할 수 있다.

 

4 보안 향상

에러 메시지를 일관되게 관리하면, 민감한 정보가 실수로 클라이언트에 노출되는 것을 방지할 수 있다.

 

5 예측 가능한 API

API를 사용하는 개발자들은 API가 예측 가능하고, 오류 상황에서 유용한 정보를 제공받는 것을 선호한다. 전역 예외 처리를 사용하면 API 사용성을 크게 향상할 수 있다.

 

 

 

4. @RestControllerAdvice?

전역에서 발생할 수 있는 예외를 처리하는데 사용된다. @ControllerAdvice + @ResponseBody의 조합으로 생각할 수 있다. 즉 예외 처리 로직을 포함하는 클래스에 적용되며, 해당 클래스 내의 메서드들이 예외를 처리하고 자동으로 응답 본문에 포함되도록 해준다.

 

 

 

5. @RestControllerAdvice의 주요 기능

전역 예외 처리

애플리케이션의 모든 컨트롤러에서 발생하는 예외를 한 곳에서 처리해 준다. 코드 중복을 줄이고, 일관성을 유지시켜 준다

 

응답 본문 자동화

REST API는 클라이언트에게 JSON이나 XML과 같은 형식으로 데이터를 반환하는 게 일반적이다. @RestControllerAdvice에 의해 처리되는 예외 메서드는 @ResponseBody가 적용된 것처럼 동작하여 예외 정보를 직렬화하여 응답 본문에 포함시킬 수 있다

 

특정 컨트롤러 범위 지정

@RestCOntrollerAdvice는 선택적으로 특정 패키지나 컨트롤러에 대해서만 적용을 시킬 수가 있다. 애플리케이션의 특정 부분에 대한 예외처리를 더 세밀하게 조정하도록 도와준다

 

 

 

6. ErrorResponse 코드

@Getter
public class ErrorResponse {
    private final LocalDateTime timestamp = LocalDateTime.now();
    private final int statusCode;
    private final String error;
    private final String message;

    public ErrorResponse(ErrorCode errorCode) {
        this.statusCode = errorCode.getHttpStatus().value();
        this.error = errorCode.getHttpStatus().name();
        this.message = errorCode.getMessage();
    }
}

timestamp에는 LocalDateTIme.now()를 사용해서 현재 시간을 넣어준다.

statusCode에는 반환할 상태코드, error에는 에러명, message에는 반환할 메시지를 넣어준다.

또한 ErrorCode를 매개변수로 받는 생성자를 만들어준다.

 

 

7. RestApiException 코드

@Getter
@RequiredArgsConstructor
public class RestApiException extends RuntimeException {
    private final ErrorCode errorCode;
}

RuntimeException을 상속받아서 에러코드를 정의한다

 

 

 

 

8. ErrorCode 코드

@Getter
@RequiredArgsConstructor
public enum ErrorCode {
    /*
     * 400 BAD_REQUEST: 잘못된 요청
     */
    BAD_REQUEST(HttpStatus.BAD_REQUEST, "Invalid request."),

    /*
     * 401 UNAUTHORIZED: 인증되지 않은 사용자의 요청
     */
    UNAUTHORIZED_REQUEST(HttpStatus.UNAUTHORIZED, "Unauthorized."),

    /*
     * 403 FORBIDDEN: 권한이 없는 사용자의 요청
     */
    FORBIDDEN_ACCESS(HttpStatus.FORBIDDEN, "Forbidden."),

    /*
     * 404 NOT_FOUND: 리소스를 찾을 수 없음
     */
    NOT_FOUND(HttpStatus.NOT_FOUND, "Not found."),

    /*
     * 405 METHOD_NOT_ALLOWED: 허용되지 않은 Request Method 호출
     */
    METHOD_NOT_ALLOWED(HttpStatus.METHOD_NOT_ALLOWED, "Not allowed method."),

    /*
     * 500 INTERNAL_SERVER_ERROR: 내부 서버 오류
     */
    INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "Server error.");


    private final HttpStatus httpStatus;
    private final String message;
}

이 클래스는 ENUM 형식으로 만들었고, 각 오류의 항목이름을 설정해 준 뒤 내부에는 에러코드 번호, 메시지를 포함하여 설정해 준다

 

 

 

 

9. GlobalExceptionHandler 코드

@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    /*
     * Developer Custom Exception: 직접 정의한 RestApiException 에러 클래스에 대한 예외 처리
     */
    @ExceptionHandler(RestApiException.class)
    protected ResponseEntity<ErrorResponse> handleCustomException(RestApiException ex) {
        ErrorCode errorCode = ex.getErrorCode();
        return handleExceptionInternal(errorCode);
    };

    // handleExceptionInternal() 메소드를 오버라이딩해 응답 커스터마이징
    private ResponseEntity<ErrorResponse> handleExceptionInternal(ErrorCode errorCode) {
        return ResponseEntity
                .status(errorCode.getHttpStatus().value())
                .body(new ErrorResponse(errorCode));
    }
}

전역적으로 발생하는 예외를 처리하기 위한 GLobalExceptionHandler 클래스

모든 컨트롤러에서 발생하는 예외를 이곳에서 한 번에 처리한다

반응형

+ Recent posts