[java][작성중]springboot 에서 예외처리하기

intro

springboot 에서 기본적인 예외처리

  • 존재하지 않는 페이지로 요청했을때 기본적으로 아래와 같이 응답값을 내려준다
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.

Mon May 17 11:28:09 KST 2021
There was an unexpected error (type=Not Found, status=404).
No message available
  • 또한 Content-Type을 application/json 로 한경우는 아래처럼 에러를 내려준다.
{
"timestamp": 1621218625595,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/err0r_test"
}
  • 이러한 에러응답은 아래와 같은 설정을 통해 제어가 가능하다
    # spring boot의 기본 properties
    server.error:
    include-exception: false # 오류 응답에 exception의 내용을 포함할지 여부 (TRUE, FALSE) 
    include-stacktrace: never # 오류 응답에 stacktrace 내용을 포함할지 여부 (ALWAYS, NEVER, ON_TRACE_PARAM)
    path: '/error' # 오류 응답을 처리할 핸들러(ErrorController)의 path 
    whitelabel.enabled: true # 브라우저 요청에 대해 서버 오류시 기본으로 노출할 페이지를 사용할지 여부 (TRUE, FALSE)
    
  • 기본적으로 어떻게 에러처리되어 응답하게 되는지는 다음에 확인해보자.
    • 우선 당장 사용해야할 부분부터…

개요

  • spring 3.2 이전 버전에서 예외를 처리하는 방식은 HandlerExceptionResolver 나 @ExceptionHandler 어노테이션을 사용하는 것이었다.
  • spring 3.2 이후부터는 @ControllerAdvice 어노테이션을 사용하는 방식으로 되었고
  • spring 5부터는 rest api에서 기본 오류처리를 위한 빠른 방법인 ResponseStatusException 클래스가 도입되었다.

    솔루션1.

  • controller 레벨에서 @ExceptionHandler 사용
  • @ExceptionHandler 를 사용하는 방법은 특정 컨트롤러에만 활성화 되어 전체적으로 관리하기가 힘들다
    public class FooController{  
      //...
      @ExceptionHandler({ CustomException1.class, CustomException2.class })
      public void handleException() {
          //
      }
    }
    

솔루션2.

  • HandlerExceptionResolver 를 정의 하는 방법인데, 지금상황에서 굳이 알필요가 있을까 싶다.

솔루션3.

  • spring 3.2 부터 @ControllerAdvice 어노테이션을 사용하면 전역적으로 @ExceptionHandler 를 관리할수 있다.
    @ControllerAdvice
    public class RestResponseEntityExceptionHandler 
    extends ResponseEntityExceptionHandler {
    
      @ExceptionHandler(value 
        = { IllegalArgumentException.class, IllegalStateException.class })
      protected ResponseEntity<Object> handleConflict(
        RuntimeException ex, WebRequest request) {
          String bodyOfResponse = "This should be application specific";
          return handleExceptionInternal(ex, bodyOfResponse, 
            new HttpHeaders(), HttpStatus.CONFLICT, request);
      }
    }
    

솔루션4.

  • spring5 부터 ResponseStatusException class를 도입하였다.
  • 장단점이있다고 하는데, 아직은 잘 모르겠..
    @GetMapping(value = "/{id}")
    public Foo findById(@PathVariable("id") Long id, HttpServletResponse response) {
      try {
          Foo resourceById = RestPreconditions.checkFound(service.findOne(id));
    
          eventPublisher.publishEvent(new SingleResourceRetrievedEvent(this, response));
          return resourceById;
       }
      catch (MyResourceNotFoundException exc) {
           throw new ResponseStatusException(
             HttpStatus.NOT_FOUND, "Foo Not Found", exc);
      }
    }
    

예제

  • @ControllerAdvice 어노테이션을 통해 전역적으로 exception 핸들링이 가능하다
    @ControllerAdvice
    public class TestExceptionHandler{
      ...
    }
    
  • 이곳에서 @ExceptionHandler 를 통해 관리가 가능하다 ```java

@ControllerAdvice public class TestExceptionHandler{

@ExceptionHandler({TestException.class})
public void handleTestException(HttpServletRequest request, TestException exception) {
    ...       
} } ```
  • 최상위 에러는 아래처럼 Exception 를 넣어서 놓치는 에러가 없도록 하자
    @ControllerAdvice
    public class TestExceptionHandler{
        
      @ExceptionHandler(Exception.class)
      public void handleException(HttpServletRequest request, Exception ex) {
          ...
      }
    }    
    

참고

  • Spring Web MVC - exception
    • https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-exceptionhandler
  • Error Handling for REST with Spring
    • https://www.baeldung.com/exception-handling-for-rest-with-spring
  • 이것 더 봐야함
    • https://supawer0728.github.io/2019/04/04/spring-error-handling/
    • 테스트 관련 아래 사항 더 보기
      • https://jaehun2841.github.io/2018/08/30/2018-08-25-spring-mvc-handle-exception/#test-case
      • https://sanghye.tistory.com/29