[Spring]컨트롤러 예외처리를 자동으로

aidenshin·2020년 3월 15일
2

Controller 를 작성하다 보면 예외처리를 반복적으로 작성해야할 때가 있다.

예를 들어 IllegalArgumentException일 경우 400(BadRequest)를 응답한다거나 알 수 없는 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를 반복적으로 사용하는 경우 내 손가락도 아프고.. 가독성도 떨어진다..

내가 좋아하는 클린코드 라는 책에는 이런 구절이 있다.

try/catch 블록은 원래 추하다. 코드 구조에 혼란을 일으키며, 정상 동작과 오류 처리 동작을 뒤섞는다.


반복적인 예외처리를 피하기 위해

Controller에서 발생하는 반복적인 예외처리를 피하기 위해 Spring의 @ExceptionHandler 를 사용해 보자

@ExceptionHandler

@ExceptionHandler 는 @Controller, @RestController가 적용된 Bean내에서 발생하는 예외를 잡아서 하나의 메서드에서 처리해주는 기능을 한다.
({ }) 안에 처리할 예외 클래스를 넣은 후 매서드로 처리 내용을 구현하면 된다.

@ControllerAdvise

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

@ControllerAdvice
@Slf4j
public class ExceptionController {

    // 400
    @ExceptionHandler({
            MemberJoinException.class,
            RuntimeException.class
    })
    public ResponseEntity<Object> BadRequestException(final RuntimeException ex) {
        log.warn("error", ex);
        return ResponseEntity.badRequest().body(ex.getMessage());
    }

    // 401
    @ExceptionHandler({ AccessDeniedException.class })
    public ResponseEntity handleAccessDeniedException(final AccessDeniedException ex) {
        log.warn("error", ex);
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(ex.getMessage());
    }

...

    // 500
    @ExceptionHandler({ Exception.class })
    public ResponseEntity<Object> handleAll(final Exception ex) {
        log.info(ex.getClass().getName());
        log.error("error", ex);
        return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }

}

@ControllerAdvice 를 통해 모든 컨트롤러에서 발생하는 예외를 잡고 @ExceptionHandler 를 통해 발생하는 예외의 종류마다 처리할 매서드를 정의한다.


// Exception Controller 설정 후 코드
@GetMapping("/api/v1/admin/members") public ResponseEntity getAllMember(Pageable pageable) {

// RuntimeException 발생 시 알아서 400에러 리턴, Exception 발생 시 500 리턴
    Page<Member> memberPage = memberFindService.getAllMemberPage(pageable);

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

설정이 완료되면 Controller에 예외를 처리하는 코드를 작성하지 않아도 알아서 설정해놓은 대로 예외를 처리해준다.
물론 직접 try/catch를 통해 예외를 처리하면 직접 처리한 것이 우선순위로 작동하게 된다.

profile
예전 블로그: https://shinilhyun.github.io/

0개의 댓글