인프런 커뮤니티 질문&답변

sumni010405님의 프로필 이미지
sumni010405

작성한 질문수

[개정판 2023-11-27] Spring Boot 3.x 를 이용한 RESTful Web Services 개발

Version 관리 - URI를 이용한 버전관리

@ExceptionHandler(MethodArgumentNotValidException.class) 예외 response 메서드 파라미터 관련하여 질문있습니다.

작성

·

739

0

안녕하세요.
유효성 체크를 위한 Validation API 사용 강의를 듣고 의문이 생겨 질문드립니다.

ResponseEntityExceptionHandler 클래스에 http 예외 response 메서드가 정의되어있다고 하셨고, 이를 오버라이딩하여 사용했을 때는

@Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
                                                                  HttpHeaders headers,
                                                                  HttpStatus status,
                                                                  WebRequest request) {
        ExceptionResponse exceptionResponse=ExceptionResponse.builder()
                .timestamp(new Date())
                .messsage(ex.getMessage())
                .details(ex.getBindingResult().toString())
                .build();
        
        return ResponseEntity.status(status).body(exceptionResponse);
    }

스크린샷 2022-10-11 오후 2.18.08.png의도한대로 exceptionResponse가 http body에 들어갔습니다.

 

제가 여기서 ResponseEntityExceptionHandler 클래스를 상속받지 않고, @ExceptionHanlder(MethodArgumentNotValidException.class)를 통해 에러를 캐치하고자 하였는데요.

@Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
                                                                  HttpHeaders headers,
                                                                  HttpStatus status,
                                                                  WebRequest request) {
        ExceptionResponse exceptionResponse=ExceptionResponse.builder()
                .timestamp(new Date())
                .messsage("Validation Failed")
                .details(ex.getBindingResult().toString())
                .build();

        return ResponseEntity.status(status).body(exceptionResponse);
    }

스크린샷 2022-10-11 오후 3.26.10.png이때는 저희가 작성한 exceptionResponse가 http body에 담기지 않는 것을 확인할 수 있었습니다.

그래서 앞서 작성한 메서드(MethodArgumentNotValidException.class만 캐치하는 메서드)를 삭제하였을 때는

@ExceptionHandler(Exception.class)
    public final ResponseEntity<Object>handleAllExceptions(Exception ex, WebRequest request){

        ExceptionResponse exceptionResponse=ExceptionResponse.builder()
                .timestamp(new Date())
                .messsage(ex.getMessage())
                .build();

        return ResponseEntity.status(HttpStatus.NOT_FOUND)
                .body(exceptionResponse);
    }

전체 에러를 잡는 메서드가 따로 있기 때문에

스크린샷 2022-10-11 오후 2.18.08.png커스텀한 에러 메시지가 응답되었습니다.

 

여기서 제가 내린 결론은

@ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
                                                                  HttpHeaders headers,
                                                                  HttpStatus status,
                                                                  WebRequest request) {
        ExceptionResponse exceptionResponse=ExceptionResponse.builder()
                .timestamp(new Date())
                .messsage("Validation Failed")
                .details(ex.getBindingResult().toString())
                .build();

        return ResponseEntity.status(status).body(exceptionResponse);
    }

해당 메서드가 MethodArgumentNotValidException.class 에러를 캐치하지만 로직을 수행하고 있지 못하다. 입니다.

 

그래서 다음과 같이 파라미터를 바꾸어줬더니

@ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex) {
        ExceptionResponse exceptionResponse=ExceptionResponse.builder()
                .timestamp(new Date())
                .messsage("Validation Failed")
                .details(ex.getBindingResult().toString())
                .build();

        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(exceptionResponse);
    }
   

에러를 캐치하고 Custom한 ResponseException을 전달받았습니다.

 

그럼 이러한 에러를 캐치하고 custom한 responseException을 만들 때 메서드의 파라미터는 어떻게 정해야 하는 건가요????

 

또한, 제가 생각한 이 과정이 맞는지 궁금합니다.

답변 1

1

Dowon Lee님의 프로필 이미지
Dowon Lee
지식공유자

안녕하세요, 이도원입니다.

오류가 발생하신 부분에 대해서 잘 정리해 주셨는데, 아래 내용에서 조금 이상한 점이 있네요.

...

"제가 여기서 ResponseEntityExceptionHandler 클래스를 상속받지 않고, @ExceptionHanlder(MethodArgumentNotValidException.class)를 통해 에러를 캐치하고자 하였는데요."

...

말씀하신 내용처럼 ResponseEntityExceptionHandler 클래스를 상속받지 않으셨다고 하면, @Override를 사용하실 수 없을텐데, 해당 코드에는 @Overriderk 되어 있어서, 질문의 내용을 완전하게 이해하기가 어려웠습니다. 다만, 마지막에 정리하신 내용을 보면

@ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
                                                                  HttpHeaders headers,
                                                                  HttpStatus status,
                                                                  WebRequest request) {
        ExceptionResponse exceptionResponse=ExceptionResponse.builder()
                .timestamp(new Date())
                .messsage("Validation Failed")
                .details(ex.getBindingResult().toString())
                .build();

        return ResponseEntity.status(status).body(exceptionResponse);
    }

위 코드는 실행이 되지 않았고,

@ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex) {
        ExceptionResponse exceptionResponse=ExceptionResponse.builder()
                .timestamp(new Date())
                .messsage("Validation Failed")
                .details(ex.getBindingResult().toString())
                .build();

        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(exceptionResponse);
    }
   

위 코드는 실행이 되었다는 것으로 이해했습니다. (맞나요??)

위와같은 상황이라면, @ExceptionHandler를 사용하실 때, 메소드의 Argument에는 정해져 있는 내용들만 선언될 수 있습니다. (대신 순서는 상관없는 것으로 압니다)

따라서, MethodArgumentNotValidationException과 WebRequset는 선언 시 문제가 되지 않지만, 이회의 HttpHeaders, HttpStatus를 같이 선언하여 사용하실 때에는 오류가 발생하고, 실제 콘솔 로그를 보시면 아래와 같은 오류를 확인해 보실 수 있습니다.

java.lang.IllegalStateException: Could not resolve parameter [1] in public org.springframework.http.ResponseEntity<java.lang.Object> com.example.myrestfulservices.exception.CustomizedResponseEntityExceptionHandler.handleMethodArgumentNotValid(org.springframework.web.bind.MethodArgumentNotValidException,org.springframework.http.HttpHeaders,org.springframework.http.HttpStatus,org.springframework.web.context.request.WebRequest): No suitable resolver

따라서, @ExceptionHandler를 사용하실 때, MethodArgumentNotValidationException만 선언해서 실행하였을 때 정상작동되었었습니다.

정리하면, @ExceptionHandler를 사용하실 때, 기존의 @Override 메소드에서 정의된 아래와 같은 인자값들을 모두 선언하여 사용하시면 No suitable resolver 오류가 발생하기 때문에, 사용하시는 인자값을 구분하여 실행하셔야 할 것 같습니다.

@ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
                                                                  HttpHeaders headers,
                                                                  HttpStatus status,
                                                                  WebRequest request) { ...

사용 가능한 인자값으로는,

Exception 객체, Request나 Response 객체, Session 객체, WebRequest 객체, Locale 객체, InputStream이나 OutputStream 객첵, Model 객체가 있습니다.

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ExceptionHandler.html

질문에 대한 답변이 되었으면 좋겠네요.

감사합니다.

sumni010405님의 프로필 이미지
sumni010405

작성한 질문수

질문하기