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
https://oingdaddy.tistory.com/314
https://tychejin.tistory.com/180
'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 |