예제를 만들자 뚱땅뚱땅

API 만들기 연습 #5 CustomException

NEWDODORIPYO 2022. 8. 29. 09:08

CustomException 처리 하기

✅개인적으로 CustomException에 대한 작업이 가장 힘들었습니다 구글링해도 잘 모르겠고 이해 안 가는 코드만 보이고 한 3일 동안은 수많은 코드를 쓰고 지우고 반복하며 지금 코드를 만들었습니다 물론 좋은 코드라고는 할 수 없지만 현재로는 최선인 것 같습니다 😭😭

Error 처리에 대한 정보를 가지는 ErrorCode 와 ErrorDTO 만들어보자

ErrorDTO

package com.apiservice.model.Error;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class ErrorDTO {

    private final int status;
    private final String message;
}

ErrorCode

package com.apiservice.model.Error;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public **enum** ErrorCode {

**BAD_REQUEST(400 ,"Bad Request"),
BAD_ENTITY(401,"Bad ENTITY");**

    private final int status;
    private final String message;

    //  Enum 클래스로 사용할 에러들을 적어준다.
    //  status 값과 error message 만 프론트에 넘겨줄 예정으로 두 개만 작성하였다.
    //  재사용성을 생각해서 범위를 너무 좁게설정하지 말고 넓은 범위로 설정해보자
}

  • ErrorCode 에서는 직접 enum으로 Errorcode 랑 message를 만들어준다
  • 기본적으로 Http 상태코드 로 있는 건 만들 필요가 없지만 상황에 따라 필요한 경우에는 이렇게 만들어준다

Handler 패키지를 만들고 CustomException 과 GlobalExceptionHandler를 만들어준다

CustomException

package com.apiservice.controller.Handler;

import com.apiservice.model.Error.ErrorCode;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class CustomException extends RuntimeException{

    private final ErrorCode errorCode;
}

GlobalExceptionHandler

package com.apiservice.controller.Handler;

import com.apiservice.model.Error.ErrorDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import static com.apiservice.model.Error.ErrorCode.BAD_ENTITY;
import static com.apiservice.model.Error.ErrorCode.BAD_REQUEST;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler({ BindException.class})
    protected ResponseEntity handleBindException(BindException ex) {

        FieldError fieldError = ex.getFieldError();

        String message = fieldError.getDefaultMessage();
        String param = fieldError.getField();

        message = message + "(" + param + ")";

        log.debug(" message : {}", message);
        log.debug(" param   : {}", param);

        return new ResponseEntity(new ErrorDTO( BAD_REQUEST.getStatus(), message + " " + BAD_REQUEST.getMessage()+ ":" + param), HttpStatus.valueOf(BAD_REQUEST.getStatus()));
    }

    @ExceptionHandler({ Exception.class })
    protected ResponseEntity handleServerException(Exception ex) {

        ex.printStackTrace();

        return new ResponseEntity(new ErrorDTO(BAD_ENTITY.getStatus(), BAD_ENTITY.getMessage()), HttpStatus.BAD_REQUEST);
    }
}
  • handleBindException 과 handleServerException 클래스가 있는데 코드를 보면 BindException 은 handleBindException에서 처리하고 나머지 예외 상황은 모두 handleServerException에서 처리하게 되어있다
  • @RestControllerAdvice 선언을 해주면 자동으로 @RestController 을 인식한다

만든 코드를 테스트해보자

  • 현재 DB 칼럼들에는 notnull 설정을 안 해둔 상태이다 그 이유는 update 할 때 모든 값을 넣는 것이 아닌 필요한 값만 update 하는 경우가 있기에 차라리 DTO에서 validation을 사용할 예정이다
  • 현재 만든 ExceptionHandler를 테스트하기 위해 잠시 member_id에 notnull 설정을 해주고 테스트를 진행했습니다

  • 아무 값도 없는 상태로 insert를 진행했고 그러니 설정한 handleBindException을 잘 타고 있다