예외 처리가 일어나는 우선 순위도 있다고 한다.
@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
);
}
}
@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이 먼저 발동되게 된다.
@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 핸들러에서 잡기.