작성
·
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);
}
의도한대로 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);
}
이때는 저희가 작성한 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);
}
전체 에러를 잡는 메서드가 따로 있기 때문에
커스텀한 에러 메시지가 응답되었습니다.
여기서 제가 내린 결론은
@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
안녕하세요, 이도원입니다.
오류가 발생하신 부분에 대해서 잘 정리해 주셨는데, 아래 내용에서 조금 이상한 점이 있네요.
...
"제가 여기서 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 객체가 있습니다.
질문에 대한 답변이 되었으면 좋겠네요.
감사합니다.