[SPRING BOOT] 예외처리 @RestControllerAdvice

song ju hee·2023년 2월 11일
0

🍀 spring 가보자고

목록 보기
1/1

@RestControllerAdvice

@ControllerAdvice와 @ResponseBody를 합쳐놓은 어노테이션이다.
@ControllerAdvice와 동일한 역할을 수행하지만, 추가적으로 @ResponseBody를 통해 객체를 리턴할 수 있다.
@RestControllerAdvice를 활용하여 공통 예외 처리(Exception Handler)를 적용해보자.

신규 api를 구현할 때마다 일관된 오류 메시지 형식으로 응답할 수 있도록 한다.

1. 에러 응답 모델 생성

public class ApiExceptionEntity {

    private String errorCode;
    private String errorMessage;
    
    @Builder
    public ApiExceptionEntity(HttpStatus status, String errorCode, String errorMessage){
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
    }
}

{
"errorCode": "E004",
"errorMessage": "중복된 아이디 입니다."
}

이러한 형식으로 클라이언트에게 넘겨주기 위해 공통 ExceptionEntitiy를 생성

2. 에러 enum class 선언

public enum ExceptionEnum {

    RUNTIME_EXCEPTION(HttpStatus.BAD_REQUEST, "E001"),
    ACCESS_DENIED_EXCEPTION(HttpStatus.UNAUTHORIZED, "E002"),
    INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "E003"),
    EXISTS_LOGINID(HttpStatus.BAD_REQUEST, "B001", "중복된 아이디 입니다."),
    VALIDATION_ID(HttpStatus.BAD_REQUEST, "B002", "아이디는 6~15자 소문자 영어로 시작, 영어 소문자와 숫자 최소 한가지씩 조합해야합니다."),
    VALIDATION_PWD(HttpStatus.BAD_REQUEST, "B003", "비밀번호는 8~16자 영대소문자, 숫자, 특수문자를 최소 한가지씩 조합해야합니다."),
    SECURITY_01(HttpStatus.UNAUTHORIZED, "S0001", "권한이 없습니다.");
    
    private final HttpStatus status;
    private final String code;
    private String message;

    ExceptionEnum(HttpStatus status, String code) {
        this.status = status;
        this.code = code;
    }

    ExceptionEnum(HttpStatus status, String code, String message) {
        this.status = status;
        this.code = code;
        this.message = message;

그리고 발생한 예외를 처리해줄 예외 클래스를 추가한다.

@Getter
public class ApiException extends RuntimeException{
    private ExceptionEnum error;

    public ApiException(ExceptionEnum e) {
        super(e.getMessage());
        this.error = e;
    }
}

3. @RestControllerAdvice 구현하기

전역적으로 에러를 처리해주는 @RestControllerAdvice를 구현하면 된다.

@RestControllerAdvice
public class marketKurlyApiException {

    @ExceptionHandler({ApiException.class})
    public ResponseEntity<ApiExceptionEntity> exceptionHandler(HttpServletRequest request, final ApiException e) {
        //e.printStackTrace();
        return ResponseEntity
                .status(e.getError().getStatus())
                .body(ApiExceptionEntity.builder()
                        .errorCode(e.getError().getCode())
                        .errorMessage(e.getError().getMessage())
                        .build());
    }

    @ExceptionHandler({RuntimeException.class})
    public ResponseEntity<ApiExceptionEntity> exceptionHandler(HttpServletRequest request, final RuntimeException e) {
        e.printStackTrace();
        return ResponseEntity
                .status(ExceptionEnum.RUNTIME_EXCEPTION.getStatus())
                .body(ApiExceptionEntity.builder()
                        .errorCode(ExceptionEnum.RUNTIME_EXCEPTION.getCode())
                        .errorMessage(e.getMessage())
                        .build());
    }

    @ExceptionHandler({AccessDeniedException.class})
    public ResponseEntity<ApiExceptionEntity> exceptionHandler(HttpServletRequest request, final AccessDeniedException e) {
        e.printStackTrace();
        return ResponseEntity
                .status(ExceptionEnum.ACCESS_DENIED_EXCEPTION.getStatus())
                .body(ApiExceptionEntity.builder()
                        .errorCode(ExceptionEnum.ACCESS_DENIED_EXCEPTION.getCode())
                        .errorMessage(e.getMessage())
                        .build());
    }

    @ExceptionHandler({Exception.class})
    public ResponseEntity<ApiExceptionEntity> exceptionHandler(HttpServletRequest request, final Exception e) {
        e.printStackTrace();
        return ResponseEntity
                .status(ExceptionEnum.INTERNAL_SERVER_ERROR.getStatus())
                .body(ApiExceptionEntity.builder()
                        .errorCode(ExceptionEnum.INTERNAL_SERVER_ERROR.getCode())
                        .errorMessage(e.getMessage())
                        .build());
    }

}

유효성 검사를 처리하지 못하면

이런식으로 응답이 넘어온다.


처음에 이해하느라 애썼다. 노션에 정리도 해보고 여러 블로그를 읽어봤지만 쉽게 이해가 가지 않았다. 하지만 여러 글들을 정리하고 곱씹어보니 이해가 조금은 가기 시작했다 (나.. 조금은 스프링에 재미를 가진걸수도? )


참고
https://annajin.tistory.com/184
https://leeys.tistory.com/30

profile
개발 꿈나무🎇

0개의 댓글