-
예외처리전략 (Exception Handler)Spring 2021. 9. 5. 20:25
스프링에서 예외처리를 해주자.
예외발생 데이터타입을 일관된 형태로 생성해서 반응하도록 설정해준다.
Error Response
먼저 예외의 형태를 잡아주는 클래스를 작성해준다. 메세지와 상태, 시간정보를 담고있다. 발생된 에러를 다음의 형태로 반환할 것이다.
import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor public class ErrorResponse { private String message; private int status; private long timestamp; }
Global Exception Handler
발생된 예외 형태에 따라서 처리를 해주는 exception handler를 작성해준다. @Controller Advice 어노테이션을 이용해서 모든 예외를 한 곳에서 처리할 수 있게 된다. 각각의 예외는 @ExceptionHandler를 통해서 예외클래스를 처리해준다.
import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; @ControllerAdvice public class GlobalExceptionHandler { //@Valid or @Validated 바인딩 에러시 발생 @ExceptionHandler(MethodArgumentNotValidException.class) protected ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException e){ ErrorResponse errorResponse = new ErrorResponse(); HttpStatus status = HttpStatus.BAD_REQUEST; errorResponse.setStatus(status.value()); errorResponse.setMessage(e.getMessage()); return new ResponseEntity<>(errorResponse, status); } //@ModelAttribute로 바인딩 에러시에 발생 @ExceptionHandler(BindException.class) protected ResponseEntity<ErrorResponse> handleBindException(BindException e){ ErrorResponse errorResponse = new ErrorResponse(); HttpStatus status = HttpStatus.BAD_REQUEST; errorResponse.setStatus(status.value()); errorResponse.setMessage(e.getMessage()); return new ResponseEntity<>(errorResponse, status); } //enum 타입 불일치로 바인딩 에러시에 발생 (ex. @RequestParam enum에러) @ExceptionHandler(MethodArgumentTypeMismatchException.class) protected ResponseEntity<ErrorResponse> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e){ ErrorResponse errorResponse = new ErrorResponse(); HttpStatus status = HttpStatus.BAD_REQUEST; errorResponse.setStatus(status.value()); errorResponse.setMessage(e.getMessage()); return new ResponseEntity<>(errorResponse, status); } //지원하지 않는 HTTP 메소드 호출시 발생 @ExceptionHandler(HttpRequestMethodNotSupportedException.class) protected ResponseEntity<ErrorResponse> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) { ErrorResponse errorResponse = new ErrorResponse(); HttpStatus status = HttpStatus.BAD_REQUEST; errorResponse.setStatus(status.value()); errorResponse.setMessage(e.getMessage()); return new ResponseEntity<>(errorResponse, status); } @ExceptionHandler(UserNotFoundException.class) public ResponseEntity<ErrorResponse> handleUserNotFoundException(UserNotFoundException e){ ErrorResponse errorResponse = new ErrorResponse(); HttpStatus status = HttpStatus.BAD_REQUEST; errorResponse.setStatus(status.value()); errorResponse.setMessage(e.getMessage()); return new ResponseEntity<>(errorResponse, status); } //Authentication 권한이 없는 경우 발생(security에서 발생시킨다) @ExceptionHandler(AccessDeniedException.class) protected ResponseEntity<ErrorResponse> handleAccessDeniedException(AccessDeniedException e) { ErrorResponse errorResponse = new ErrorResponse(); HttpStatus status = HttpStatus.BAD_REQUEST; errorResponse.setStatus(status.value()); errorResponse.setMessage(e.getMessage()); return new ResponseEntity<>(errorResponse, status); } @ExceptionHandler(IllegalAccessException.class) protected ResponseEntity<ErrorResponse> handleIllegalAccessException(IllegalAccessException e){ ErrorResponse errorResponse = new ErrorResponse(); HttpStatus status = HttpStatus.BAD_REQUEST; errorResponse.setStatus(status.value()); errorResponse.setMessage(e.getMessage()); return new ResponseEntity<>(errorResponse, status); } @ExceptionHandler(Exception.class) protected ResponseEntity<ErrorResponse> handleException(Exception e){ ErrorResponse errorResponse = new ErrorResponse(); HttpStatus status = HttpStatus.NOT_FOUND; errorResponse.setStatus(status.value()); errorResponse.setMessage(e.getMessage()); return new ResponseEntity<>(errorResponse, status); } }
Custom Error
위에서 작성된 에러케이스 중 User Not Found 에러의 경우 custom으로 작성해주었다. 상위에러를 상속받아서 정의해준다.
public class UserNotFoundException extends RuntimeException { public UserNotFoundException(String message) { super(message); } public UserNotFoundException(String message, Throwable cause) { super(message, cause); } public UserNotFoundException(Throwable cause) { super(cause); } }
에러를 발생시킬 경우에 다음과 같이 사용해준다.
public UserDTO get(Integer id) throws UserNotFoundException { try { User user = repo.findById(id).get(); UserDTO userDTO = new UserDTO(user); return userDTO; }catch (NoSuchElementException ex){ throw new UserNotFoundException("This User doesn't exist"); }
'Spring' 카테고리의 다른 글
@ManyToMany, @OneToMany, @ManyToOne관계 작성하기 (0) 2021.09.05 MultipartFile 파일업로드(with. react) (0) 2021.09.05 JWT 토큰을 이용해서 로그인 인증 구현하기 (9) 2021.09.05 WebSocket 사용해서 react와 함께 채팅구현하기 (Stomp사용하기) (1) 2021.09.05 @Many to Many 혹은 연관관계에서 stackOverFlow 에러 발생시 (0) 2021.08.17