본문 바로가기

Project/Table_of_Organization_Management_System

Error 처리를 해보자

728x90

ApiResponse 를 사용하자 에서 보았듯이 응답의 형태를, 사용하는 프로젝트 요구에 맞게 통일시켜줄 필요가 있다. 이는 Error 에서도 마찬가지이다. 때문에 간단하게 Error 처리를 한번 해보자.

 

프로젝트에 범용적으로 쓰일 BusinessException 을 만들어보자.

BusinessException 은 RuntimeException 으로 만들것이다.

 

BusinessException.java

public class BusinessException extends RuntimeException {

  private final ErrorCode errorCode;

  public BusinessException(ErrorCode errorCode) {
    super(errorCode.name());
    this.errorCode = errorCode;
  }

  public BusinessException(String message) {
    super(message);
    this.errorCode = null;
  }

  public BusinessException(ErrorCode errorCode, String message) {
    super(message);
    this.errorCode = errorCode;
  }

  public ErrorCode getErrorCode() {
    return errorCode;
  }


  public String getErrorMessage() {
    return super.getMessage();
  }
}

 

BusinessException 를 만들었기에 BusinessException 를 상속한 커스텀 Error 를 쉽게 생산해 낼 수 있다.

 

EntityNotFoundException.java

public class EntityNotFoundException extends BusinessException {

  public EntityNotFoundException() {
    super(ErrorCode.NO_SUCH_ENTITY_ERROR);
  }

  public EntityNotFoundException(ErrorCode errorCode) {
    super(errorCode);
  }

  public EntityNotFoundException(ErrorCode errorCode, String message) {
    super(errorCode, message);
  }

  public EntityNotFoundException(String message) {
    super(message);
  }
}

 

DataNotFoundException.java

 

public class DataNotFoundException extends BusinessException {

  public DataNotFoundException() {
    super(ErrorCode.NO_SUCH_DATA_ERROR);
  }

  public DataNotFoundException(ErrorCode errorCode) {
    super(errorCode);
  }

  public DataNotFoundException(ErrorCode errorCode, String message) {
    super(errorCode, message);
  }

  public DataNotFoundException(String message) {
    super(message);
  }
}

 

 

Spring 에서 API @ExceptionHandler를 처리할 @RestControllerAdvice 를 만들자

 

ApiExceptionHandler.java

 

@Slf4j
@RestControllerAdvice
public class ApiExceptionHandler {

  private final ApplicationEventPublisher applicationEventPublisher;

  @Autowired
  public ApiExceptionHandler(final ApplicationEventPublisher applicationEventPublisher) {
    this.applicationEventPublisher = applicationEventPublisher;
  }

  /**
   * 사용자의 실수로인한 Error(처리하지 않아도 될)
   */
  @ResponseStatus(HttpStatus.OK)
  @ExceptionHandler({
      BusinessException.class,
      DataNotFoundException.class
  })
  public ApiResponse<String> handleWaning(BusinessException e) {
    return handleBusinessException(e, false);
  }

  /**
  * 확인이 필요한 에러(Event를 발생시킬)
  */
  @ResponseStatus(HttpStatus.OK)
  @ExceptionHandler({
      EntityNotFoundException.class
  })
  public ApiResponse<String> handleCustomException(BusinessException e) {
    return handleBusinessException(e, true);
  }

  private ApiResponse<String> handleBusinessException(BusinessException e, boolean isDataError) {
    String errorMessage = isDataError ?
        "ApiExceptionHandler > InvalidDataException > exception: {}, {}"
        : "ApiExceptionHandler > BusinessException > exception: {}, {}";

    log.error(errorMessage, e.getMessage(), e);

    ErrorCode ec = e.getErrorCode() == null ? ErrorCode.BAD_REQUEST_ERROR : e.getErrorCode();
    String message = e.getMessage();

    if (isDataError && e.getErrorCode() != null) {
      applicationEventPublisher.publishEvent(new ExceptionEvent(this, message, e));
    }

    return ApiResponseGenerator.fail(ec, e.getMessage());
  }
 }

 

위의 코드를 보면 ApplicationEventPublisher 를 통해 Error 발생에 대한 이벤트를 날리는데,  ApplicationEvent 를 상속받은 ExceptionEvent.java 를 만들고 이 Event 를 Listen하는 @EventListener 를 만들어서, Error 발생시  에러에 대한 이벤트를 슬랙 알림 등으로 날려 활용할 수 있다. 

 

Event 참고 블로그

 

 

728x90