java spring

Spring boot Exception 처리

윤돌_99 2021. 7. 30. 21:53

Cotroller를 사용하다보면 예외처리를 반복적으로 수행해야 할 때가 있다.

예를 들어, IllegalArgumentException일 경우, 400으로 응답

알 수 없는 Exception의 경우 500(INTERNAL_SERVER_ERROR)를 발생시키거나

 

@GetMapping("/api/v1/members")
public ResponseEntity getAllMember(Pageable pageable) {

    Page<Member> memberPage;
    
    // 반복적으로 발생하는 Try-Catch
    try {
          memberPage = memberFindService.getAllMemberPage(pageable);
    } catch (RuntimeException re) {
        return ResponseEntity.badRequest().build();
    } catch (Exception e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }

    return ResponseEntity.ok().body(MemberAdminDto.Info.of(memberPage));
}

위와 같이 try-catch를 반복적으로 사용하는 경우, 코드의 양이 늘어나고 가독성이 떨어진다.

 

이러한 Controller에서 발생하는 반복적인 예외처리를 피하기 위해 Spring의 @ExceptionHandler를 사용한다.

 

@ExceptionHandler

@ExceptionHandler는 @Controller, @RestController가 적용된 Bean내에서 발생하는 예외를 잡아서 하나의 메세드에서 처리하는 기능을 한다.

{{ }}안에 처리할 예외 클래스를 넣은 후 메서드로 처리 내용을 구현하면 된다.

 

@ControllerAdvise

@ControllerAdvise는 모든 @Controller 즉, 전역에서 발생할 수 있는 예외를 잡아 처리해주는 annotation이다. 

 

 

 

Spring boot 어플리케이션에서 예외처리하는 방법은 3가지이다.

1. 전역 처리 Global Level using - @ControllerAdvice(추천)

2. 컨트롤러단에서 처리 Controller Level using - @ExceptionHandler

3. 메소드 단위에서 처리 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 와 @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();}  
  
  
}

 

- handlerBaseException(BaseException e): Exception, CustomException1 과 CustomException1 클래스들의 예외를 잡는다.

- handleException(Exception e): Exception 클래스의 자식들의 모든 예외를 처리한다.

 

<참고>

https://springboot.tistory.com/33

 

스프링부트 : REST 어플리케이션에서 예외처리하기

스프링부트 : REST어플리케이션에서 예외처리하기 (원문소스: http://www.ekiras.com/2016/02/how-to-do-exception-handling-in-springboot-rest-application.html) 기억할 점 스프링 부트 어플리케이션에서 예외..

springboot.tistory.com

 

https://oingdaddy.tistory.com/314

 

Springboot @RestControllerAdvice 사용해 Exception 처리하기

Spring을 처음 배울때 AOP 부분을 이해하기 힘들었다. 막 Spring이 본격적으로 쓰이던 시기라 설명도 다 직역으로 되어 있고 (영어를 잘 못함..) 머리도 썩 좋은 편이 아니라 어려웠던것 같다. 역시 정

oingdaddy.tistory.com

https://leeys.tistory.com/30

 

[Spring Boot] Rest API 만들기(4) 예외 처리 @RestControllerAdvice

Rest Api 구현중 오류 메시는 개발자가 의도한 오류(Custom Exception)와 예상치 못한 System Exception으로 구분됩니다. 이번 포스팅에서는 이러한 예외상황에 대해 @RestControllerAdvice를 활용하여 공통 예외.

leeys.tistory.com

 

https://tychejin.tistory.com/180

 

[Spring Boot] REST API 게시판 만들기(13) - 예외 처리 및 테스트

스프링 MVC에서는 애플리케이션에서 발생하는 예외를 처리할 때는 @ExceptionHandler 어노테이션과 @ControllerAdvice 어노테이션을 사용합니다. @ExceptionHandler은 전체 애플리케이션의 예외 처리를 하지 못

tychejin.tistory.com