Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
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 31
Archives
Today
Total
관리 메뉴

코딩블로그

[Spring]ErrorResponse & Exception 만들기 본문

Spring

[Spring]ErrorResponse & Exception 만들기

_hanbxx_ 2023. 12. 19. 18:50
728x90

밥메이트 프로젝트를 진행하면서 Exception다루는 클래스를 작성해보았습니다

 

BaseErrorCode

public interface BaseErrorCode {
    public ErrorReason getErrorReason();
}

 

BaseException

@Getter
@AllArgsConstructor
public class BaseException extends RuntimeException {
    private final BaseErrorCode errorCode;

    public ErrorReason getErrorReason() {
        return this.errorCode.getErrorReason();
    }
}

 

Dto/ErrorReason

@Getter
public class ErrorReason {
    private final int status;
    private final String code;
    private final String reason;

    @Builder
    private ErrorReason(int status, String code, String reason) {
        this.status = status;
        this.code = code;
        this.reason = reason;
    }

    public static ErrorReason of(int status, String code, String reason) {
        return ErrorReason.builder().status(status).code(code).reason(reason).build();
    }
}


MeetingErrorCode

@Getter
@AllArgsConstructor
public enum MeetingErrorCode implements BaseErrorCode {
    FULL_CAPACITY_ERROR(BAD_REQUEST,"MEETING_404","인원이 다 찼습니다"),
    MEETING_NOT_FOUND(BAD_REQUEST,"MEETING_404","모임이 존재하지 않습니다"),
    ALREADY_PARTICIPATED_ERROR(BAD_REQUEST,"MEETING_404","이미 참여한 모임입니다"),
    NOT_ALLOWED_TO_PARTICIPATE_ERROR(BAD_REQUEST,"MEETING_404","생성한 모임에는 참여할 수 없습니다");

    private final int status;
    private final String code;
    private final String reason;

    @Override
    public ErrorReason getErrorReason() {
        return ErrorReason.of(status, code, reason);
    }
}

 

MeetingNotFoundException

public class MeetingNotFoundException extends BaseException {
    public MeetingNotFoundException() {
        super(MeetingErrorCode.MEETING_NOT_FOUND);
    }
}

 

마지막으로 

GlobalExceptionHandler 클래스를 만들어서 위에 만든 코드들이 작동하도록 설정해주어야 합니다

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

	//주로 HTTP 요청을 처리하는 도중에 발생한 예외를 처리합니다
    protected ResponseEntity<Object> handleExceptionInternal(
            Exception ex,
            @Nullable Object body,
            HttpHeaders headers,
            HttpStatus statusCode,
            WebRequest request) {
        log.error("HandleInternalException", ex);
        final HttpStatus status = (HttpStatus) statusCode;
        final ErrorReason errorReason =
                ErrorReason.of(status.value(), status.name(), ex.getMessage());
        final ErrorResponse errorResponse = ErrorResponse.from(errorReason);
        return super.handleExceptionInternal(ex, errorResponse, headers, status, request);
    }

	
    @Nullable
    protected ResponseEntity<Object> handleMethodArgumentNotValid(
            MethodArgumentNotValidException ex,
            HttpHeaders headers,
            HttpStatus status,
            WebRequest request) {
        final HttpStatus httpStatus = (HttpStatus) status;
        final List<FieldError> errors = ex.getBindingResult().getFieldErrors();
        final Map<String, Object> fieldAndErrorMessages =
                errors.stream()
                        .collect(
                                Collectors.toMap(
                                        FieldError::getField, FieldError::getDefaultMessage));
        final String errorsToJsonString =
                fieldAndErrorMessages.entrySet().stream()
                        .map(e -> e.getKey() + " : " + e.getValue())
                        .collect(Collectors.joining("|"));
        final ErrorReason errorReason =
                ErrorReason.of(status.value(), httpStatus.name(), errorsToJsonString);
        final ErrorResponse errorResponse = ErrorResponse.from(errorReason);
        return ResponseEntity.status(HttpStatus.valueOf(errorReason.getStatus()))
                .body(errorResponse);
    }

    @Nullable
    protected ResponseEntity<Object> handleHttpMessageNotReadable(
            HttpMessageNotReadableException ex,
            HttpHeaders headers,
            HttpStatus status,
            WebRequest request) {
        log.error("HttpMessageNotReadableException", ex);
        final GlobalErrorCode globalErrorCode = GlobalErrorCode.HTTP_MESSAGE_NOT_READABLE;
        final ErrorReason errorReason = globalErrorCode.getErrorReason();
        final ErrorResponse errorResponse = ErrorResponse.from(errorReason);
        return ResponseEntity.status(INTERNAL_SERVER_ERROR).body(errorResponse);
    }

    // 비즈니스 로직(UseCase) 에러 처리
    @ExceptionHandler(BaseErrorException.class)
    public ResponseEntity<ErrorResponse> handleBaseErrorException(
            BaseErrorException e, HttpServletRequest request) {
        log.error("BaseErrorException", e);
        final ErrorReason errorReason = e.getErrorCode().getErrorReason();
        final ErrorResponse errorResponse = ErrorResponse.from(errorReason);
        return ResponseEntity.status(HttpStatus.valueOf(errorReason.getStatus()))
                .body(errorResponse);
    }

    //따로 Exception으로 빼서 처리하지 않은 에러를 모두 처리해줍니다.
    @ExceptionHandler(Exception.class)
    protected ResponseEntity<ErrorResponse> handleException(
            Exception e, HttpServletRequest request) {
        log.error("Exception", e);
        final ContentCachingRequestWrapper cachedRequest =
                new ContentCachingRequestWrapper(request);
        final GlobalErrorCode globalErrorCode = GlobalErrorCode._INTERNAL_SERVER_ERROR;
        final ErrorReason errorReason = globalErrorCode.getErrorReason();
        final ErrorResponse errorResponse = ErrorResponse.from(errorReason);
        return ResponseEntity.status(INTERNAL_SERVER_ERROR).body(errorResponse);
    }
}

 

  • @RestControllerAdvice
    : @RestControllerAdvice는 @ControllerAdvice와 달리 @ResponseBody가 붙어 있어 응답을 Json으로 내려준다

 

결과

728x90

'Spring' 카테고리의 다른 글

spring boot이용해서 EmployeeManager 사이트 구현하기  (0) 2023.04.29