-
spring @ControllerAdvice, @ExceptionHandlerSpring/Spring 기본 지식 2021. 4. 7. 15:27반응형
코딩을 하다가 몇개의 Exception은 처리가 쉬운게 이것이 여러개인 경우 또는 Error Message 처리는 어떻게 할까? 라는 의문으로 시작하게 되어 Advice를 공부하게 되었다
코드를 작성을 하게 되면 Exception처리가 매우 길어지거나, 처리하기가 매우 힘들어진다. 그렇기 때문에 스프링에서는 크게 ControllerAdvice, ExceptionHandler 2가지 방법으로 에러처리를 진행한다.
해당코드는 gitHub 확인해주세요
ExceptionHandler
Controller나 RestController에서 발생되는 에러를 메소스에서 처리하는 기능을 가졌다. 하지만 단점이 있는데 단점을 알아 보자.
단점
- Controller 또는 RestController에서만 작동이 된다.
- ExceptionHandler를 등록해 줘야 한다.
- Cotnroller나 RestController에 에러가 외부에서 작동이 되지 않는다.
코드
ExceptionHandlerController
@RestController @RequiredArgsConstructor public class ExceptionHandlerController { private final ExceptionHandlerService service; @GetMapping("/v1") public ResponseEntity playNullPointException() { return new ResponseEntity<>(service.nullPointExceptionError(), HttpStatus.OK); } @GetMapping("/v1/sample") public ResponseEntity playSampleException() { return new ResponseEntity<>(service.sampleException(), HttpStatus.OK); } @ExceptionHandler({NullPointException.class}) public String nullPointExceptionHandler() { return "Null 에러 발생"; } }
ExceptionHandlerController2
@RestController @RequiredArgsConstructor public class ExceptionHandlerController2 { private final ExceptionHandlerService service; @GetMapping("/v2") public ResponseEntity playNullPointException(){ return new ResponseEntity<>(service.nullPointExceptionError(), HttpStatus.OK); } @GetMapping("/v2/sample") public ResponseEntity playSampleException(){ return new ResponseEntity<>(service.sampleException(), HttpStatus.OK); } @ExceptionHandler({NullPointException.class, SampleException.class}) public String nullPointExceptionHandler(){ return "Null 또는 SampleException 에러 발생"; } }
ExceptionHandlerService
@Service public class ExceptionHandlerServiceImpl implements ExceptionHandlerService{ @Override public SampleDto nullPointExceptionError() { throw new NullPointException("NullPointException 발생"); } @Override public SampleDto sampleException() { throw new SampleException("SampleException 발생"); } }
Exception 들
public class SampleException extends RuntimeException{ public SampleException(String message) { super(message); } } public class NullPointException extends RuntimeException{ public NullPointException(String message) { super(message); } }
코드 설명 및 실행 결과
ExceptionHandlerController와 ExceptionHandlerController2의 코드를 보게 된다면 SampleException를 처리 했냐 안했냐의 차이점이 존재한다. 이를 기억하고 코드를 실행시키면 실행결과가 아래와 같이 발생이 된다.
@ControllerAdvice
ExceptionHandler와 다르게 Exception들을 한군데서 처리할 수 있는 기능을 가졌다.
@ControllerAdvice public class GlobalExceptionHandler { /** * javax.validation.Valid or @Validated 으로 binding error 발생시 발생한다. * HttpMessageConverter 에서 등록한 HttpMessageConverter binding 못할경우 발생 * 주로 @RequestBody, @RequestPart 어노테이션에서 발생 */ @ExceptionHandler(MethodArgumentNotValidException.class) protected ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { log.error("handleMethodArgumentNotValidException", e); ErrorsResource resource = new ErrorsResource(ErrorCode.INVALID_INPUT_VALUE, e); return new ResponseEntity<>(resource, HttpStatus.BAD_REQUEST); } /** * @ModelAttribut 으로 binding error 발생시 BindException 발생한다. * ref https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-modelattrib-method-args */ @ExceptionHandler(BindException.class) protected ResponseEntity handleBindException(BindException e) { log.error("handleBindException", e); ErrorsResource resource = new ErrorsResource(ErrorCode.INVALID_INPUT_VALUE, e); return new ResponseEntity<>(resource, HttpStatus.BAD_REQUEST); } /** * enum type 일치하지 않아 binding 못할 경우 발생 * 주로 @RequestParam enum으로 binding 못했을 경우 발생 */ @ExceptionHandler(MethodArgumentTypeMismatchException.class) protected ResponseEntity handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) { log.error("handleMethodArgumentTypeMismatchException", e); ErrorsResource resource = new ErrorsResource(ErrorCode.METHOD_NOT_ALLOWED, (Errors) e); return new ResponseEntity<>(resource, HttpStatus.BAD_REQUEST); } /** * 지원하지 않은 HTTP method 호출 할 경우 발생 */ @ExceptionHandler(HttpRequestMethodNotSupportedException.class) protected ResponseEntity handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) { log.error("handleHttpRequestMethodNotSupportedException", e); ErrorsResource resource = new ErrorsResource(ErrorCode.METHOD_NOT_ALLOWED); return new ResponseEntity<>(resource, HttpStatus.METHOD_NOT_ALLOWED); } /** * Authentication 객체가 필요한 권한을 보유하지 않은 경우 발생합 */ @ExceptionHandler(AccessDeniedException.class) protected ResponseEntity handleAccessDeniedException(AccessDeniedException e) { log.error("handleAccessDeniedException", e); ErrorsResource resource = new ErrorsResource(ErrorCode.HANDLE_ACCESS_DENIED); return new ResponseEntity<>(resource, HttpStatus.valueOf(ErrorCode.HANDLE_ACCESS_DENIED.getStatus())); } /** * RestApi 통신시 파라미터가 다른경우 발생함 * @param e * @return */ @ExceptionHandler(HttpMessageNotReadableException.class) protected ResponseEntity handleHttpMessageNotReadableException(HttpMessageNotReadableException e) { log.error("handleHttpMessageNotReadableException", e); ErrorsResource resource = new ErrorsResource(ErrorCode.PARAMETER_BIND_ERROR); return new ResponseEntity<>(resource, HttpStatus.valueOf(ErrorCode.HANDLE_ACCESS_DENIED.getStatus())); } @ExceptionHandler(BusinessException.class) protected ResponseEntity handleBusinessException(BusinessException e) { log.error("handleEntityNotFoundException", e); final ErrorCode errorCode = e.getErrorCode(); ErrorsResource resource = new ErrorsResource(errorCode); return new ResponseEntity<>(resource, HttpStatus.valueOf(errorCode.getStatus())); } @ExceptionHandler(Exception.class) protected ResponseEntity handleException(Exception e) { log.error("handleEntityNotFoundException", e); ErrorsResource resource = new ErrorsResource(ErrorCode.INTERNAL_SERVER_ERROR); return new ResponseEntity<>(resource, HttpStatus.INTERNAL_SERVER_ERROR); } }
참고
반응형'Spring > Spring 기본 지식' 카테고리의 다른 글
spring transaction roll back 처리 (0) 2021.06.20 Spring DataSourceTransactionManager (0) 2020.07.01 MyBatis 속성 (0) 2020.05.06 Spring AOP 설정방법 - @annotation 두 번째(백기선님) (0) 2020.03.30 Spring AOP 설정방법 - execution (0) 2020.03.30