[Spring Boot] GlobalExceptionHandler, CustomException 사용법

어디든 배우자·2023년 11월 6일
0

GlobalExceptionHandler - 전역 예외 처리 핸들러 만들기

예외 처리가 일어나는 우선 순위도 있다고 한다.

A 예외 처리 - 글로벌 예외 처리

@RestControllerAdvice
public class GlobalExceptionHandler {
  
  	private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(Exception.class)
    public ResponseEntity<Object> handleGlobalException(Exception ex) {
      
		logger.error(ex.getMessage());
      
        return new ResponseEntity<>(
                Map.of(
                        WebConstants.STATUS,WebConstants.FAIL,
                        WebConstants.MESSAGE,WebConstants.UNKNOWN_ERROR
                ),
                HttpStatus.INTERNAL_SERVER_ERROR
        );

    }
    
}

B 예외 처리 - 컨트롤러 예외 처리

@Api(tags = "테스트 Controller")
@RestController
public class TestController {
  
  	private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
 
    @ExceptionHandler(Exception.class)
    public ResponseEntity<Object> handleGlobalException(Exception ex) {
      
		logger.error(ex.getMessage());
      
        return new ResponseEntity<>(
                Map.of(
                        WebConstants.STATUS,WebConstants.FAIL,
                        WebConstants.MESSAGE,WebConstants.UNKNOWN_ERROR
                ),
                HttpStatus.INTERNAL_SERVER_ERROR
        );

    }

}

여기서 A랑 B 중에 어떤 예외 처리가 먼저 발생할까? 정답은 B 이다.

글로벌 예외 처리에서도 우선 순위가 있다.

@RestControllerAdvice
public class GlobalExceptionHandler {
  
  	private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(Exception.class)
    public ResponseEntity<Object> handleGlobalException(Exception ex) {

      	logger.error(ex.getMessage());
      
        return new ResponseEntity<>(
                Map.of(
                        WebConstants.STATUS,WebConstants.FAIL,
                        WebConstants.MESSAGE,WebConstants.UNKNOWN_ERROR
                ),
                HttpStatus.INTERNAL_SERVER_ERROR
        );

    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResponseEntity<Object> handleGlobalException(MissingServletRequestParameterException ex) {
      
      	logger.error(Objects.requireNonNull(ex.getMessage()));

        return new ResponseEntity<>(
                Map.of(
                        WebConstants.STATUS,WebConstants.FAIL,
                        WebConstants.MESSAGE,WebConstants.UNKNOWN_ERROR
                ),
                HttpStatus.BAD_REQUEST
        );

    }

}

Exception은 부모 클래스라고 생각하면 편하다.
즉, MissingServletRequestParameterException이 Exception에 자식 클래스 이니까
아래 핸들러인 MissingServletRequestParameterException이 먼저 발동되게 된다.

CustomException - 커스텀 예외 처리 만들기

@Getter
public class CustomException extends Exception{
    private final ErrorCode errorCode;

    public CustomException(String message, ErrorCode errorCode){
        super(message);
        this.errorCode = errorCode;
    }
}


@Data
public class ErrorResponse {
    private int status;
    private String errorCode;
    private String message;


    public ErrorResponse(ErrorCode errorCode){
        this.status = errorCode.getStatus();
        this.errorCode = errorCode.getErrorCode();
        this.message = errorCode.getMessage();
    }
}


@Getter
@RequiredArgsConstructor
public enum ErrorCode{
    NOT_FOUND(404,"COMMON-ERR-404","PAGE NOT FOUND"),
    INTER_SERVER_ERROR(500,"COMMON-ERR-500","INTER SERVER ERROR")
    ;

    private int status;
    private String errorCode;
    private String message;

    ErrorCode(int status, String errorCode, String message) {
        this.status = status;
        this.errorCode = errorCode;
        this.message = message;
    }
}

이렇게 클래스들을 구성하고, enum 클래스에 커스텀 하여 만들면 된다.

사용법

그냥 전역 예외 처리는 try catch 없이도 발동한다.
근데 커스텀 예외 처리는 왜 사용 하는가라고 물어본다면,
뭔가를 확실하게 구별하고 싶을때? 저는 그렇게 사용합니다.

public String JWTDecoder(HttpServletRequest req) throws CustomException {

        try{
            return tokenDecoderService.decoderJWT(req, WebConstants.CLAIMS_ID);
        }catch (Exception e){
            throw new CustomException(WebConstants.EXCEPTION_500, ErrorCode.TOKEN_DECODER_ERROR);
        }

 }

상세하게 분류하고 싶으면 try/catch를 사용하여 CustomException으로 처리.

public String JWTDecoder(HttpServletRequest req) throws CustomException {

    if(!tokenDecoderService.decoderJWT(req, WebConstants.CLAIMS_ID)){
    	throw new CustomException(WebConstants.EXCEPTION_500, ErrorCode.TOKEN_DECODER_ERROR);
    }

	return tokenDecoderService.decoderJWT(req, WebConstants.CLAIMS_ID);

 }

아니면 이런식으로 처리 가능.
그 외에 대다수 에러는 그냥 Exception.class 핸들러에서 잡기.

저는 이렇게 사용할 뿐, 정답이 아닙니다. 피드백 정말 환영합니다.

profile
다 흡수하기.

0개의 댓글