티스토리 뷰

1. Global Exception Handler

GlobalExceptionHandler는 애플리케이션에서 발생하는 다양한 예외를 중앙에서 관리하고 처리하기 위한 클래스입니다. Spring에서는 @RestControllerAdvice와 @ExceptionHandler를 활용하여 전역 예외 처리를 구현합니다.

주요 기능

  • 특정 예외(CoreException)에 대해 맞춤형 응답을 반환.
  • 예외의 종류에 따라 적절한 HTTP 상태 코드를 매핑.
  • 애플리케이션의 나머지 부분에 영향을 주지 않고 예외를 처리하며 로그를 기록.
  • 예상치 못한 예외는 handleAllExceptions에서 처리.
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(CoreException.class)
    public ResponseEntity<ErrorResponse> handleCoreException(CoreException coreException) {
        logError(coreException.getErrorType());

        ErrorResponse errorResponse = new ErrorResponse(
                coreException.getErrorType().getErrorCode(),
                coreException.getErrorType().getMessage(),
                coreException.getPayload()
        );

        HttpStatus status = mapToHttpStatus(coreException.getErrorType().getErrorCode());
        return new ResponseEntity<>(errorResponse, status);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleAllExceptions(Exception exception) {
        log.warn("Exception occur: ", exception);
        ErrorResponse errorResponse = new ErrorResponse(ErrorCode.DB_ERROR, "서버 내부 오류가 발생했습니다.", null);
        return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    private HttpStatus mapToHttpStatus(ErrorCode errorCode) {
        return switch (errorCode) {
            case NOT_FOUND -> HttpStatus.NOT_FOUND;
            case CLIENT_ERROR -> HttpStatus.BAD_REQUEST;
            default -> HttpStatus.INTERNAL_SERVER_ERROR;
        };
    }

    private void logError(ErrorType errorType) {
        LogLevel logLevel = errorType.getLogLevel();
        switch (logLevel) {
            case WARN -> log.warn(errorType.getMessage());
            case ERROR -> log.error(errorType.getMessage());
            default -> log.info(errorType.getMessage());
        }
    }
}

2. CoreException

CoreException은 사용자 정의 예외 클래스이며, 애플리케이션에서 발생한 오류에 대해 처리할 수 있는 예외를 정의합니다. ErrorType과 payload를 포함하여, 오류 처리에 필요한 정보를 함께 제공합니다.

주요 기능

  • 예외의 종류를 정의하는 ErrorType을 포함합니다.
  • Payload는 오류와 관련된 추가 데이터를 포함할 수 있는 필드입니다.
  • 예외가 발생할 때, ErrorType에 정의된 메시지를 사용하여 예외 메시지를 제공합니다.
public class CoreException extends RuntimeException {
    private final ErrorType errorType;
    private final Object payload;

    public CoreException(ErrorType errorType, Object payload) {
        super(errorType.getMessage());
        this.errorType = errorType;
        this.payload = payload;
    }

    public ErrorType getErrorType() {
        return errorType;
    }

    public Object getPayload() {
        return payload;
    }
}

3. ErrorType

ErrorType은 애플리케이션에서 발생할 수 있는 다양한 오류를 정의하는 열거형 클래스입니다. 각 오류는 특정 ErrorCode, 오류 메시지, 그리고 로그 레벨을 함께 정의하여, 일관된 에러 처리를 가능하게 합니다.

주요 기능

  • 각 오류에 대한 HTTP 상태 코드와 메시지를 설명을 제공
  • 사용자에게 전달할 오류 메시지를 정의합니다.
  • 로그 레벨을 정의하여, 오류 발생 시 로그를 남길 때의 중요도를 설정합니다.
@Getter
@RequiredArgsConstructor
public enum ErrorType {

    BALANCE_NOT_FOUND(ErrorCode.NOT_FOUND, "잔액을 찾을 수 없습니다.", LogLevel.WARN),
    BALANCE_LIMIT_AMOUNT(ErrorCode.CLIENT_ERROR, "충전 금액이 초과되었습니다.", LogLevel.INFO),
    BALANCE_LESS_THAN_ZERO(ErrorCode.CLIENT_ERROR, "충전 금액은 0보다 커야 합니다.", LogLevel.INFO),
    BALANCE_EXCEEDS_AVAILABLE(ErrorCode.CLIENT_ERROR, "사용하려는 금액이 잔액을 초과할 수 없습니다.", LogLevel.INFO)
    ... 
    // 기타 에러 타입 정의


    private final ErrorCode errorCode;
    private final String message;
    private final LogLevel logLevel;

    public ErrorCode getErrorCode() {
        return errorCode;
    }

    public String getMessage() {
        return message;
    }

    public LogLevel getLogLevel() {
        return logLevel;
    }
}

4. ErrorResponse

ErrorResponse는 예외가 발생했을 때 클라이언트에게 반환할 오류 응답 데이터를 정의하는 record입니다. 이를 통해 오류 응답을 간결하게 관리할 수 있습니다.

주요 기능

  • 오류의 종류를 정의합니다.
  • 오류 메시지를 정의합니다.
  • 추가적인 데이터를 포함할 수 있는 필드로, 오류 처리와 관련된 상세 정보를 클라이언트에 전달합니다.
public record ErrorResponse(ErrorCode errorCode, String message, Object payload) {
}

5. ErrorCode

ErrorCode는 애플리케이션에서 발생할 수 있는 HTTP 상태 코드와 그에 대한 설명을 정의하는 열거형 클래스입니다. 이를 통해 오류 발생 시 적절한 상태 코드와 설명을 클라이언트에게 전달할 수 있습니다.

주요 기능

  • 각 오류 코드에 대한 설명을 정의합니다. 이를 통해 클라이언트는 오류의 원인을 이해할 수 있습니다.
  • 각 오류에 매핑되는 HTTP 상태 코드를 제공합니다.
public enum ErrorCode {
    NOT_FOUND("404: 리소스를 찾을 수 없음"),
    DB_ERROR("500: 데이터베이스 오류 발생"),
    CLIENT_ERROR("400: 클라이언트 요청 오류");

    private final String desc;

    ErrorCode(String desc) {
        this.desc = desc;
    }

    public String getDesc() {
        return desc;
    }
}

6. Logging Filter

LoggingFilter는 HTTP 요청 및 응답의 상세 정보를 로깅하는 기능을 제공합니다. 모든 요청과 응답의 내용을 캡처하여 디버깅과 모니터링에 유용합니다.

주요 기능

  • 요청의 URL, HTTP 메서드, 바디 등을 캡처하고 로깅.
  • 응답의 상태 코드, 헤더, 바디 등을 로깅.
  • Spring Filter를 활용하여 요청-응답 흐름의 양쪽을 처리.
@Component
@Slf4j
public class LoggingFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;

        ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(httpServletRequest);
        ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(httpServletResponse);

        logRequestDetails(wrappedRequest);
        chain.doFilter(wrappedRequest, wrappedResponse);
        logResponseDetails(wrappedResponse);

        wrappedResponse.copyBodyToResponse();
    }

    private void logRequestDetails(ContentCachingRequestWrapper request) {
        log.info("Request URL: " + request.getRequestURI());
        log.info("Request Method: " + request.getMethod());
        log.info("Request Body: " + new String(request.getContentAsByteArray()));
    }

    private void logResponseDetails(ContentCachingResponseWrapper response) {
        log.info("Response Status: " + response.getStatus());
        log.info("Response Body: " + new String(response.getContentAsByteArray()));
    }
}

7. Token Interceptor

TokenInterceptor는 요청 헤더에 포함된 token 값의 유효성을 검증하고, 이를 기반으로 요청을 허용하거나 차단하는 역할을 합니다. 특정 경로에 대해 토큰 검증 로직을 적용할 수 있습니다.

주요 기능

  • 요청 헤더에서 토큰을 추출.
  • 서비스(WaitingQueueService)를 호출하여 토큰의 유효성을 확인.
  • 유효하지 않은 토큰일 경우, HTTP 상태 코드를 401 (Unauthorized)로 설정하고 요청 차단.
@Component
@RequiredArgsConstructor
public class TokenInterceptor implements HandlerInterceptor {

    private final WaitingQueueService waitingQueueService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("token");

        if (!waitingQueueService.getWaitingQueueCheck(token)) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }

        return true;
    }
}

8. Web Config

Spring의 WebMvcConfigurer를 활용하여 특정 API 경로에 대해 TokenInterceptor를 적용합니다.

주요 기능

  • 인터셉터를 특정 경로(/api/concerts/**)에만 적용하도록 설정.
  • 다른 경로에는 영향을 미치지 않음.
@RequiredArgsConstructor
@Configuration
public class WebConfig implements WebMvcConfigurer {

    private final TokenInterceptor tokenInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(tokenInterceptor)
                .addPathPatterns("/api/concerts/**");
    }
}

요약

  • Global Exception Handler: 예외를 중앙에서 처리하고, 일관된 오류 응답을 반환.
  • CoreException: 사용자 정의 예외로, 오류 종류와 추가 정보를 처리.
  • ErrorType Enum: 다양한 오류를 정의하고, 각 오류에 대한 메시지와 로깅 수준 설정.
  • ErrorResponse: 클라이언트에 반환할 오류 응답 데이터를 정의.
  • ErrorCode: 오류 코드와 설명을 정의하여 적절한 상태 코드 제공.
  • Logging Filter: HTTP 요청 및 응답을 로깅하여 디버깅과 모니터링을 강화.
  • Token Interceptor: 요청 헤더의 토큰을 검증하여 인증되지 않은 요청 차단

끝.

 

728x90
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함