2022/02/11 한 번에 끝내는 Spring 완.전.판 초격차 패키지 Online.

김석진·2022년 2월 11일
0
post-thumbnail

글로벌 예외처리 기법_01

자바 같은경우 checkedException된 예외를 try & catch로 잡아서 특정한 결과값으로 만든 후 모든 exception이 없도록 코드를 많이 짰었다.

Controller-DMakerController

ExceptionHandler

 @ResponseStatus(value = HttpStatus.CONFLICT)
    @ExceptionHandler(DMakerException.class)
    public DMakerErrorResponse handlerException(DMakerException e, HttpServletRequest request) {
        log.error("errorCode: {}, url: {}, message: {}", e.getDMakerErrorCode(),request.getRequestURI(),e.getMessage());
        return DMakerErrorResponse.builder()
                .errorCode(e.getDMakerErrorCode())
                .errorMessage(e.getDetailMessage())
                .build();
    }

DMakerException이 발생하는경우 이 메소드안으로 진입
로그를이용해 errorCode와 에러발생한 url,메세지를 찍는 핸들러를 만들어 줬다

DTO- DMakerErrorResponse

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class DMakerErrorResponse {
    private DMakerErrorCode errorCode;
    private String errorMessage;
}

예외처리 테스트

동일한 개발자를 추가했을때 설정한 로그와 DMakerErrorResponse가 제대로 세팅 되는지 테스트

라는 조건을 두번 생성하였다.

결과

2022-02-11 17:19:52.370 ERROR 3860 --- [nio-8080-exec-3] c.d.d.D.controller.DMakerController : errorCode: DUPLICATED_MEMBER_ID, url: /create-developer, message: MemberId가 중복되는 개발자가 있습니다.

서버상의 로그도 보여주고 사용자에게도 정돈된 메세지를 보여줄수 있는것을 확인할 수 있다.

결론

이런 식으로 요즘은 정확한 에러코드와 메세지를 내려주는 식으로 개발하는게 추세라고 하셨다.

내부적인 로직에서 문제가 발생했을 때 에러 결과를 넘기고 넘기는 식(계속보내는식)은 로직 복잡도를 높이고 유지보수성 낮고 재활용성이 떨어지는 코드를 만들기때문에 피하는게 좋다.

exception시 각 코드마다 Exception을 처리하기위해 try catch를 사용하는게 아닌 ExceptionHandler를 통해서 처리 할 수 있다 라는 것을 배울 수 있었다.

예외처리를 제대로 안했을 때의 문제점_01

조금더 글로벌한(예를 들어 Controller를 하나더 추가한 상황)
또 ExceptionHandler가 필요하다. application이 더 커지고 그러면 Controller가 10~20이상 생길수 있는데 ExceptionHandler를 Controller마다 추가를 하면 반복적이고 불필요한 코드가 될 수 있다.

요즘에 많이 하는 방법으로 Exception을 각 컨트롤러에서 처리하는 게 아니라 GlobalException을 만드는 것이다.

Exception-DMakerExceptionHandler

@RestControllerAdvice :
각 컨트롤러에다가 조언을 해주는 애노테이션이다.
전역적인 ExceptionHandler를 만들 수 있다.

일일히 들어가있던 ExceptionHandler들을 전부 지금 생성한 GlobalExceptionHandler에 추가함

@Slf4j
@RestControllerAdvice
public class DMakerExceptionHandler {

    @ResponseStatus(value = HttpStatus.CONFLICT)
    @ExceptionHandler(DMakerException.class)
    public DMakerErrorResponse handlerException(DMakerException e, HttpServletRequest request) {
        log.error("errorCode: {}, url: {}, message: {}", e.getDMakerErrorCode(),request.getRequestURI(),e.getMessage());
        return DMakerErrorResponse.builder()
                .errorCode(e.getDMakerErrorCode())
                .errorMessage(e.getDetailMessage())
                .build();
    }

    @ExceptionHandler(value = {
            HttpRequestMethodNotSupportedException.class,
            MethodArgumentNotValidException.class
    })
    public DMakerErrorResponse handleBadRequest(
            Exception e, HttpServletRequest request
    ){
        log.error(" url: {}, message: {}", request.getRequestURI(),e.getMessage());
        return DMakerErrorResponse.builder()
                .errorCode(INVALID_REQUEST)
                .errorMessage(INVALID_REQUEST.getMessage())
                .build();
    }

    //- 이 Exception은 뜨면 안좋은거다.. 최후의 보류
    @ExceptionHandler(value = {
            Exception.class
    })
    public DMakerErrorResponse handleException(
            Exception e, HttpServletRequest request
    ){
        log.error(" url: {}, message: {}", request.getRequestURI(),e.getMessage());
        return DMakerErrorResponse.builder()
                .errorCode(INTERNAL_SERVER_ERROR)
                .errorMessage(INTERNAL_SERVER_ERROR.getMessage())
                .build();
    }
}

결과 테스트

  • create-developer를 POST->PUT으로 변경후 Exception Test:

2022-02-11 20:16:17.499 ERROR 9624 --- [nio-8080-exec-1] c.d.d.D.e.DMakerExceptionHandler : url: /create-developer, message: Request method 'PUT' not supported

  • NOT-NULL이여야하는 필수값을 null로 생성

결과:

서버에서의 결과
2022-02-11 20:18:18.989 ERROR 9624 --- [nio-8080-exec-6] c.d.d.D.e.DMakerExceptionHandler : url: /create-developer, message: Validation failed for argument [0] in public com.developer.dmaker.Dmaker.dto.CreateDeveloperResponsecom.developer.dmaker.Dmaker.controller.DMakerController.createDevelopers(com.developer.dmaker.Dmaker.dto.CreateDeveloperResponse com.developer.dmaker.Dmaker.controller.DMakerController.createDevelopers(com.developer.dmaker.Dmaker.dto.CreateDeveloperRequest): [Field error in object 'request' on field 'developerSkillType': rejected value [null]; codes [NotNull.request.developerSkillType,NotNull.developerSkillType,NotNull.com.developer.dmaker.Dmaker.type.DeveloperSkillType,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [request.developerSkillType,developerSkillType]; arguments []; default message [developerSkillType]]; default message [널이어서는 안됩니다]]

이렇게 예외처리를 하는 이유:

  1. 정의되지않은 에러메세지를 보여주는 경우에는 상대방이 처리하기 까다롭고 장애가 발생할 수 있다. 그래서 우리가 정의한 에러메세지를 보내줄 수 잇는게 상대방이 처리할 때 좋다.
profile
주니어 개발자 되고싶어요

0개의 댓글