[Spring] 사용자 정의 예외 활용하기

GuruneLee·2022년 1월 12일
1

Let's Study 공부해요~

목록 보기
11/36

관련 포스트: 220111 CustomException 리팩토링

CustomException 활용하기

CustomException 이란?

말 그대로 사용자 정의 예외이다. Java 에서 정의해 놓은 수많은 예외가 있지만, 앱을 개발하다보면 당연하게도 자신의 로직과 완전히 맞는 예외를 찾기가 힘든 상황이 온다. 이 때, Java 의 Exception (혹은 RuntimeException) 을 상속받는 예외 클래스를 만들어서 이를 던지고 받고 물고 뜯고 하면 된다.

예시

1. custom checked exception
예를 들어, new File() 에서 파일을 못찾는 경우엔 FileNotFoundException 이 발생된다.

try (Scanner file = new Scanner(new File(fileName))) {
    if (file.hasNextLine()) return file.nextLine();
} catch(FileNotFoundException e) {
    // Logging, etc 
}

그런데 이게 진짜 없는건지, 이름이 잘못된건지 분류하고 싶을 수 있지 않은가?
이럴때 Exception 을 상속받는 IncorrectFileNameException 을 만들어서 파일이름이 잘못 된 경우를 따로 빼보자

// IncorrectFileNameExceptoin 정의
public class IncorrectFileNameException extends Exception { 
    public IncorrectFileNameException(String errorMessage, Throwable cause) {
        super(errorMessage, cause);
    }
}

// 활용
try (Scanner file = new Scanner(new File(fileName))) {
    if (file.hasNextLine())
        return file.nextLine();
} catch (FileNotFoundException e) {
    if (!isCorrectFileName(fileName)) {
        throw new IncorrectFileNameException("Incorrect filename : " + fileName, cause);
    }
    //...
}
  • Exception 을 상속받으면 CheckedException 이 되어서, 처리하지 않으면 컴파일시 에러가 나게된다.

2. custom unchecked exception
위 상황에서 파일에 읽을 내용이 없을 때 예외를 발생시켜야 한다고 가정하자. 이 예외는 실행하고 있을때만 발견할 수 있으므로 RuntimeException 을 상속받는 IncorrectFileExtentionException 을 만들어서 활용해보자.

// IncorrectFileExtentionException 정의
public class IncorrectFileExtensionException 
  extends RuntimeException {
    public IncorrectFileExtensionException(String errorMessage, Throwable err) {
        super(errorMessage, err);
    }
}

// 활용
try (Scanner file = new Scanner(new File(fileName))) {
    if (file.hasNextLine()) {
        return file.nextLine();
    } else {
        throw new IllegalArgumentException("Non readable file");
    }
} catch (FileNotFoundException err) {
    if (!isCorrectFileName(fileName)) {
        throw new IncorrectFileNameException(
          "Incorrect filename : " + fileName , err);
    }
    
    //...
} catch(IllegalArgumentException err) {
    if(!containsExtension(fileName)) {
        throw new IncorrectFileExtensionException(
          "Filename does not contain extension : " + fileName, err);
    }
    
    //...
}

[Spring] 예외처리 분리 및 통합

예외 처리란 아주아주 어렵고 복잡하다. 이게 개념적으로만 복잡한 것이 아니라 코드도 복잡하게 만들어버리는 경우가 많다. Spring 에서는 이렇게 예외를 처리하는 로직을 한 곳에서 모아서 할 수 있게 만든 어노테이션이 있다.
바로 @ExceptionHandler@ControllerAdvice 이다.

@ExceptionHandler

Controller 로 등록된 빈 내에서 발생하는 예외를 잡아서 하나의 메서드에서 처리해주는 기능을 함. 특정 컨트롤러에 대해서만 활성화 되는만큼, 범용적으로 사용할 수 없다. 한 컨트롤러에 할당되는 큰 단위의 catch 구문이라고 생각하면 된다.

public class MyClass {
	...
    @ExceptionHandelr({MyException01.class, MyException02.class}) 
    public void handleException(Exception ex) {
    	// 로깅
        // 에러 처리
    }
}

- @ExceptionHandler 의 파라미터로 하나만 들어갈 수도 있고, 여러개 들어갈 수도 있다. (여러개 들어갈때는 중괄호 {} 넣어주기)

- 메서드의 반환자료형, 이름 등은 맘대로

- 또, 받은 예외를 파라미터로 받을 수 있다 (안받을 수도 있다)

@ControllerAdvice

Spring 공식 문서에서 다음과 같이 소개되어 있다.

Specialization of @Component for classes that declare @ExceptionHandler, @InitBinder, or @ModelAttribute methods to be shared across multiple @Controller classes.

그러니깐, ExceptionHandler 와 InitBinder, ModelAttribute 를 Controller 전역에 공유하게끔 한다 라는 말이다.

@RestControllerAdvice

A convenience annotation that is itself annotated with @ControllerAdvice and @ResponseBody.

예외처리를 할 때, @ControllerAdvice 와 @ResponseBody 를 같이 써서 Restful 하게 응답을 때리는 상황이 많았나보다. 두개를 이어 붙여놓은 @RestControllerAdvice 를 만들어놨다.

@ExceptionHandler 와 @ControllerAdvice 함께 사용하기

다음과 같이 사용하면, 컨트롤러에서 발생된 모든 예외를 이 한 클래스에서 관리할 수 있게 된다.

@ControllerAdvice
public class 예외처리 {
	@ExceptionHandler(Exception.class)
	protected void handle() {
		// 뭔가 함
	}
}

@ExceptionHandler 가 모오오오든 컨트롤러에 등록된것과 같은 효과를 준다.
물론 이렇게 'Exception' 을 받아서 처리하면 호되게 혼날 수 있다.


ref
https://www.baeldung.com/java-new-custom-exception
https://jeong-pro.tistory.com/195
https://recordsoflife.tistory.com/30

profile
Today, I Shoveled AGAIN....

0개의 댓글