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
[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
'java spring' 카테고리의 다른 글
Spring Boot Rest API image 파일 전송 (0) | 2021.08.15 |
---|---|
spring boot JWT 실습(1) (0) | 2021.07.31 |
DAO, DTO, Service (0) | 2021.07.29 |
[Java Spring MVC] Maria DB와 MyBatis로 로그인 화면 만들기(3) (0) | 2021.02.06 |
[Java Spring MVC] Maria DB와 MyBatis로 로그인 화면 만들기(2) (1) | 2021.02.06 |