기억할 점
스프링 부트 어플리케이션에서 예외처리하는 방법은 3가지다:
- 전역 처리 Global Level using - @ControllerAdvice
- 컨트롤러단에서 처리 Controller Level using - @ExceptionHandler
- 메소드단위 처리 Method Level using - try/catch
REST 어플리케이션에서 예외처리하기
예외처리를 테스트하기위에 3가지 예외를 만들것이다:
- 모든 커스텀 예외의 부모가 될 BaseException.
- Base Exception을 확장한 CustomException1.
- Base Exception을 확장한 CustomException2.
다음의 메소드들을 만든다
- ex1() throws BaseException
- ex2() throws CustomException1
- ex3() throws CustomException2
- ex4() throws NullPointerException
- ex5() throws NumberFormatException
이제 위에 언급한 방법을을 사용하여 이들 예외를 어떻게 처리하는지 둘러보자
방법 1 : @ControllerAdvice를 사용한 전역 처리Global Exception Handling
클래스에 @ControllerAdvice and @RestController. 를 어노테이션을 추가하면 REST 응답을 리턴하게 될 것이다.
- @ControllerAdvice는 당신의 스프링 어플리케이션에게 이 클래스가 당신의 어플리케이션의 예외처리를 맡을 거라고 알려주게 된다.
- @RestController 는 이 클래스를 컨트롤러로 만들어주고 이 클래스가 응답을 렌더할 수 있게 해준다.
- @ExceptionHandler 어노테이션을 사용하여 예외를 처리할 클래스를 정의한다. ( 기본클래스는 모두 상속되거나 확장된 클래스를 처리할 것이다)
- 당신은 @ResponseStatus 어노테이션을 사용하여 예외의 응답 상태를 설정할 수 있다.
HomeController.class
- package com.ekiras.controller;
- import com.ekiras.exception.BaseException;
- import com.ekiras.exception.CustomException1;
- import com.ekiras.exception.CustomException2;
- import org.springframework.web.bind.annotation.ExceptionHandler;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
- /**
- * @author ekansh
- * @since 19/2/16
- */
- @RestController
- @RequestMapping({"","/"})
- public class HomeController {
- @RequestMapping("/ex1")
- public String ex1(){
- // 전역 처리자 메소드 handleBaseException에 잡힐 것이다.
- throw new BaseException("Base Exception");
- }
- @RequestMapping("/ex2")
- public String ex2(){
- //전역 처리자 메소드 handleBaseException에 잡힐 것이다.
- throw new CustomException1();
- }
- @RequestMapping("/ex3")
- public String ex3(){
- // 전역 처리자 메소드 handleBaseException에 잡힐 것이다.
- throw new CustomException2();
- }
- @RequestMapping("/ex4")
- public String ex4(){
- //전역 처리자 메소드 handleBaseException에 잡힐 것이다.
- throw new NullPointerException("null pointer exception");
- }
- @RequestMapping("/ex5")
- public String ex5(){
- // 컨트롤러 예외 처리자 메소드 nfeHandler에 잡힐 것이다.
- throw new NumberFormatException("number format exception");
- }
- /**
- * 이 컨트롤러 내에서 발생하는 모든 Number Format 예외를 처리한다 *
- * */
- @ExceptionHandler(value = NumberFormatException.class)
- public String nfeHandler(NumberFormatException e){
- return e.getMessage();
- }
- }
GlobalExceptionHandler.class
- package com.ekiras.handler.exception;
- import com.ekiras.exception.BaseException;
- import org.springframework.http.HttpStatus;
- import org.springframework.web.bind.annotation.ControllerAdvice;
- import org.springframework.web.bind.annotation.ExceptionHandler;
- import org.springframework.web.bind.annotation.ResponseStatus;
- import org.springframework.web.bind.annotation.RestController;
- /**
- * @author ekansh
- * @since 19/2/16
- */
- @ControllerAdvice
- @RestController
- public class GlobalExceptionHandler {
- @ResponseStatus(HttpStatus.BAD_REQUEST)
- @ExceptionHandler(value = BaseException.class)
- public String handleBaseException(BaseException e){
- return e.getMessage();
- }
- @ExceptionHandler(value = Exception.class)
- public String handleException(Exception e){return e.getMessage();}
- }
- handleBaseException(BaseException e) :: BaseException, CustomException1 과 CustomException2 클래스들의 예외를 잡는다.
- handleException(Exception e) :: Exception클래스의 자식들의 모든 예외를 처리한다.
알림 :: 만일 BaseException 또는 그의 자식 예외가 발생하면 handleException() 메소드가 아닌 handleBaseException()이 이 예외를 잡을 것이다.
방법 2 : @ExceptionHandler를 사용한 컨트롤러단 예외처리
- @ExceptionHandler(value = NumberFormatException.class)
- public String nfeHandler(NumberFormatException e){
- return e.getMessage();
- }
HomeController.java 에 있는 위의 코드는 이 컨트롤러내에서 발생하는 모든 NumberFormatException를잡을 것이다. 다른 컨트롤러에서 발생하는 NumberFormatException는 처리하지않는다.