예외다 우와
- e.getMessage() : 에러의 원인을 간단하게 출력합니다.(어째서 에러가 발생했는지 보여주기만한다.. num이 애러라면 num만나옴)
- e.toString() : 에러의 Exception 내용과 원인을 출력합니다.
(num이 에러인데 무슨 예외로 인한 것인지 원인 이유를 보여주나 발생위치는 보여주지 않는다)
- e.printStackTrace() : 에러의 발생근원지를 찾아서 단계별로 에러를 출력합니다.
(이유와 어느 클래스에서 발생했는지를 알려준다)
그런데 예외에도 꼭 해결해야하는 예외와 안해도 되는예외가있는데.
Checked Exception(해야하는 예외) vs Unchecked Exception(지나가는 예외)
Checked Exception 컴파일시 알고있던거
Unchecked Exception 런타임 실행시 발생되는 예외
호출한 쪽으로 던질 때 명확한 의미를 전달하기 위해 다른 예외로 전환하여 던지는 방법
1. 예를 들어 Checked Exception 중 복구가 불가능한 예외가 잡혔다면 이를 Unchecked Exception으로 전환하여서 다른 계층에서 일일이 예외를 선언할 필요가 없도록 할 수도 있다.
2.호출한 쪽에서 예외를 받아서 처리할 때 좀 더 명확하게 인지할 수 있도록 돕기 위한 방법이다.
3. SQLException을 중복예외로 바꿔 발생시킬수있다.
참조 사이트1
서블릿에서 예외가 발생하면 다음과 같은 방식으로 진행이 된다
흐름을 글로 작성하자면
1. WAS(톰캣) -> 필터 -> 서블릿(디스패처 서블릿) -> 인터셉터 -> 컨트롤러
-> 컨트롤러(예외발생) -> 인터셉터 -> 서블릿(디스패처 서블릿) -> 필터 -> WAS(톰캣)
-> WAS(톰캣) -> 필터 -> 서블릿(디스패처 서블릿) -> 인터셉터 -> 컨트롤러(BasicErrorController)
1.불필요한 호출이 발생 한다.
2.예외가 발생하면 다시 오류페이지를 찾기 위해 인터셉터 서블릿을 거치게 된다.
매우 비효율 적이다.
3.비효율적인 이유는 이미 처리를 했는데 한번더 처리가 되기 때문이다.
1.서블릿에서 예외 처리 페이지를 만들기 위해 WebServerCustomizerd를 만든다.
2.예외 종류에 따라 HTML 을 추가 해야 된다.
3.ErrorPageController 를 만들어서 예외를 따로 처리 해야된다.
스프링은 위 과정(스프링 부트의 오류 페이지)을 자동으로 처리 해준다.
BasicErrorController 에서 처리를 해주기 때문이다.
개발자는 그냥 페이지만 등록 해주면 된다.
- DefaultErrorAttributes는 전체 항목들에서 설정에 맞게 불필요한 속성들을 제거한다.
- timestamp: 에러가 발생한 시간
- status: 에러의 Http 상태
- error: 에러 코드
- path: 에러가 발생한 uri
- exception: 최상위 예외 클래스의 이름(설정 필요)
- message: 에러에 대한 내용(설정 필요)
- errors: BindingExecption에 의해 생긴 에러 목록(설정 필요)
- trace: 에러 스택 트레이스(설정 필요)
server.error.include-message: always
server.error.include-binding-errors: always
server.error.include-stacktrace: always
server.error.include-exception: false
Spring은 아래와 같은 도구들로 ExceptionResolver를 동작시켜 에러를 처리할 수 있는데, 각각의 방식 대해 자세히 살펴보도록 하자.
[ @ResponseStatus ]
어노테이션 이름에서 예측가능하듯이 @ResponseStatus는 에러 HTTP 상태를 변경하도록 도와주는 어노테이션이다. @ResponseStatus는 다음과 같은 경우들에 적용할 수 있다.
한계점
[ ResponseStatusException ]
ResponseStatusException는 HttpStatus와 함께 선택적으로 reason과 cause를 추가할 수 있고, 언체크 예외을 상속받고 있어 명시적으로 에러를 처리해주지 않아도 된다.
한계점
@ExceptionHandler는 매우 유연하게 에러를 처리할 수 있는 방법을 제공하는 기능이다.
ExceptionHandler는 @ResponseStatus와 달리 에러 응답(payload)을 자유롭게 다룰 수 있다는 점에서 유연하다.
우리는 이러한 ControllerAdvice를 이용함으로써 다음과 같은 이점을 누릴 수 있다.
한계점
여러 ControllerAdvice가 있을 때 @Order 어노테이션으로 순서를 지정하지 않는다면 Spring은 ControllerAdvice를 임의의 순서로 처리할 수 있으므로 일관된 예외 응답을 위해서는 이러한 점에 주의해야 한다.
[ Spring의 예외 처리 흐름 ]
1. ExceptionHandlerExceptionResolver가 동작함
1. 예외가 발생한 컨트롤러 안에 적합한 @ExceptionHandler가 있는지 검사함
2. 컨트롤러의 @ExceptionHandler에서 처리가능하다면 처리하고, 그렇지 않으면 ControllerAdvice로 넘어감
3. ControllerAdvice안에 적합한 @ExceptionHandler가 있는지 검사하고 없으면 다음 처리기로 넘어감
2. ResponseStatusExceptionResolver가 동작함
1. @ResponseStatus가 있는지 또는 ResponseStatusException인지 검사함
2. 맞으면 ServletResponse의 sendError()로 예외를 서블릿까지 전달되고, 서블릿이 BasicErrorController로 요청을 전달함
3. DefaultHandlerExceptionResolver가 동작함
1. Spring의 내부 예외인지 검사하여 맞으면 에러를 처리하고 아니면 넘어감
4. 적합한 ExceptionResolver가 없으므로 예외가 서블릿까지 전달되고, 서블릿은 SpringBoot가 진행한 자동 설정에 맞게 BasicErrorController로 요청을 다시 전달함