[Code-State] SECTION-3 Spring Error Handling

유형찬·2022년 10월 26일
0

Code States

목록 보기
16/21

Spring Error Handling

Introduction

Spring 에서 Exception 처리를 위한 방법에 대해 알아보자.

기본적으로 Spring 에서는 Exception 을 처리하기 위해 @ControllerAdvice 를 사용한다.

현재는 @RestControllerAdvice 를 사용하는 것이 더욱 편리하다. 아무래도 React + Spring 을 사용하는 경우가 많기 때문이다.

서버와 클라이언트가 분리되어 있기 때문에, 서버에서는 @RestControllerAdvice 를 사용하는 예제로 알아보자.

@RestControllerAdvice

@RestControllerAdvice@ControllerAdvice 와 동일한 기능을 하지만, @ResponseBody 가 추가되어 있다.

@ResponseBody 이것은 Json 형태로 응답을 보내기 위한 어노테이션이다.

@RestControllerAdvice 를 사용하면, @ExceptionHandler 를 사용하여 Exception 을 처리할 수 있다.

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = {Exception.class})
    public ResponseEntity<ErrorResponse> handleException(Exception e) {
        ErrorResponse errorResponse = new ErrorResponse();
        errorResponse.setMessage(e.getMessage());
        errorResponse.setCode("EXCEPTION");
        return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

@RestControllerAdvice 어노테이션을 사용하면 전역적으로 에러를 관리 할 수 있다.

{
    "code": "EXCEPTION",
    "message": "test"
}

위와 같이 Error Message 를 custom 할 수 있기 때문에 Client 에서 에러를 처리하기가 편리하다.

@ExceptionHandler

@ExceptionHandler@ControllerAdvice 에서 사용할 수 있는 어노테이션이다.

@ExceptionHandler 를 사용하면, 특정 Exception 을 처리할 수 있다.

enum Type 으로 Custom Exception 을 만들어서 사용할 수 있다.

public enum ErrorCode {
    INVALID_INPUT_VALUE(400, "C001", " Invalid Input Value"),
    METHOD_NOT_ALLOWED(405, "C002", " Invalid Input Value"),
    HANDLE_ACCESS_DENIED(403, "C003", "Access is Denied"),
    INTERNAL_SERVER_ERROR(500, "C004", "Server Error"),
    ENTITY_NOT_FOUND(400, "C005", "Entity Not Found");

    private final String code;
    private final String message;
    private final int status;

    ErrorCode(final int status, final String code, final String message) {
        this.status = status;
        this.code = code;
        this.message = message;
    }

    public String getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

    public int getStatus() {
        return status;
    }
}
public class CustomException extends RuntimeException {
    private ErrorCode errorCode;

    public CustomException(ErrorCode errorCode) {
        super(errorCode.getMessage());
        this.errorCode = errorCode;
    }

    public ErrorCode getErrorCode() {
        return errorCode;
    }
}

Runtime Exception 을 상속받아서 Custom Exception 을 만들 수 있다.
Enum Class 에서 정의한 error code 와 Message를 exception 때 넘겨 줄 수 있다.

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = {CustomException.class})
    public ResponseEntity<ErrorResponse> handleCustomException(CustomException e) {
        ErrorResponse errorResponse = new ErrorResponse();
        errorResponse.setMessage(e.getErrorCode().getMessage());
        errorResponse.setCode(e.getErrorCode().getCode());
        return new ResponseEntity<>(errorResponse, HttpStatus.valueOf(e.getErrorCode().getStatus()));
    }
}

위는 이제 커스텀한 Exception 을 처리하는 예제이다.

보면 알겠지만 @ExceptionHandler 에서 CustomException.class 를 넘겨주면, CustomException 을 처리할 수 있다.

@RestController
public class TestController {

    @GetMapping("/test")
    public String test() {
        throw new CustomException(ErrorCode.ENTITY_NOT_FOUND);
    }
}
{
    "code": "C005",
    "message": "Entity Not Found"
}

Json 응답이 잘 나오는 것을 확인 할 수 있다.

Return ResponseEntity VS Not Return ResponseEntity

일반적으로 Http Status 가 동적으로 변할 수 있는 경우 ResponseEntity 를 사용하고, Http Status 가 정적인 경우 ResponseEntity 를 사용하지 않는다.

정적인 경우에는 @ResponseStatus 를 사용하면 된다.

@ExceptionHandler(value = {NullPointerException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleNullPointerException(NullPointerException e) {
    ErrorResponse errorResponse = new ErrorResponse();
    errorResponse.setMessage(e.getMessage());
    errorResponse.setCode("NULL_POINTER_EXCEPTION");
    return errorResponse;
}

위 같은 경우는 ErrorResponse를 바로 Return 해주었고 Http Status 를 400으로 설정해주었다.

끝!

profile
rocoli에요

0개의 댓글