목차
Spring Boot Rest API - ExceptionHandling 존재하지 않는 id값에 대한 예외처리 추가 저장되지 않은 User를 조회할 경우 UserNotFoundException 예외가 발생하도록 예외처리한다.
UserController.java
@GetMapping("/users/{id}") public User retrieveUser (@PathVariable int id) { User user = service.findOne(id); if (user == null ){ throw new UserNotFoundException (String.format("ID[%s] not found" , id )); } return user; }
예외처리하는 Exception 클래스 생성 ResponseStatus 를 이용해 HttpStatus.NOT_FOUND 옵션을 설정할 경우 UserNotFoundException 예외가 발생했을때 Http Status Code 404(Not Found) 가 반환된다.
UserNotFoundException.java
@ResponseStatus(HttpStatus.NOT_FOUND) public class UserNotFoundException extends RuntimeException { public UserNotFoundException (String message) { super (message); } }
예외시 보내는 새로운 메시지 형식을 정의 위와 같이 에러 메시지가 반환되면 불필요한 내용들이 많다. 언제, 어떤 메시지가 발생했는지, 어떤 원인에 의해 발생했는지 필요한 정보만 담는 ExceptionResponse 클래스를 생성한다.
ExceptionResponse.java
@Data @AllArgsConstructor @NoArgsConstructor public class ExceptionResponse { private Date timestamp; private String message; private String details; }
ExceptionHandler 를 이용한 예외 처리하기
Controller에서 발생한 Exception을 다루기 위한 방법, ExceptionHandler 어노테이션을 이용해 명시된 예외, 명시된 예외 자식 클래스 예외가 발생했을 때 예외 처리를 해준다. 예외를 생략한 경우에는 Method 파라미터에 명시된 예외가 지정된다.
Controller 에서 등록되지 않은 사용자에 대한 조회 요청이 들어왔을 때 UserNotFoundException 이 발생한다.
UserNotFoundException 예외를 처리하기 위해서 ExceptionHandler 어노테이션을 통해 해당 예외를 처리한다.
UserController.class
@GetMapping("/users/{id}") public User retrieveUser (@PathVariable int id) { User user = service.findOne(id); if (user == null ){ throw new UserNotFoundException (String.format("ID[%s] not found" , id )); } return user; } @ExceptionHandler(UserNotFoundException.class) public final ExceptionResponse handleUserNotFoundException (Exception ex, WebRequest request) { ExceptionResponse exceptionResponse = new ExceptionResponse (new Date (), ex.getMessage(), request.getDescription(false )); return exceptionResponse; }
Http Status Code 다루기 ExceptionHandler 를 이용해 Controller에서 발생한 예외를 처리하는 경우 예외가 발생했음에도 Http Status Code가 200 으로 떨어지게 된다. ResponseStatus 어노테이션, ResponseEntity 를 사용해 클리언트에게 적절한 상태 코드를 반환해줄 수 있다.
ResponseStatus 어노테이션 사용한 방법 @ResponseStatus(HttpStatus.NOT_FOUND) @ExceptionHandler(UserNotFoundException.class) public final ExceptionResponse handleUserNotFoundException (Exception ex, WebRequest request) { ExceptionResponse exceptionResponse = new ExceptionResponse (new Date (), ex.getMessage(), request.getDescription(false )); return exceptionResponse; }
ResponseEntity 사용한 방법 @ExceptionHandler(UserNotFoundException.class) public final ResponseEntity<Object> handleUserNotFoundException (Exception ex, WebRequest request) { ExceptionResponse exceptionResponse = new ExceptionResponse (new Date (), ex.getMessage(), request.getDescription(false )); return new ResponseEntity (exceptionResponse, HttpStatus.NOT_FOUND); }
@ControllerAdvice @RestControllerAdvice
@ControllerAdvice @RestControllerAdvice 는 Controller, RestController 마다 정의된 ExceptionHandler를 한 곳에 모아 관리하고 처리할 수 있게 도와준다.
지정된 Controller, RestController 에 ExceptionHandler, InitBinder 기능을 부여한다.
지정된 Controller가 없을 경우 모든 Controller에 적용한다.
우선순위는 자세한 것이 높은 우선순위를 갖는다.
CustomizedResponseEntityExceptionHandler.java
@RestController @ControllerAdvice public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExceptionHandler { @ExceptionHandler(Exception.class) public final ResponseEntity<Object> handleAllExceptions (Exception ex, WebRequest request) { ExceptionResponse exceptionResponse = new ExceptionResponse (new Date (), ex.getMessage(), request.getDescription(false )); return new ResponseEntity (exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR); } @ExceptionHandler(UserNotFoundException.class) public final ResponseEntity<Object> handleUserNotFoundException (Exception ex, WebRequest request) { ExceptionResponse exceptionResponse = new ExceptionResponse (new Date (), ex.getMessage(), request.getDescription(false )); return new ResponseEntity (exceptionResponse, HttpStatus.NOT_FOUND); } }