Spring Rest API - ExceptionHandling

목차

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

// path variable을 이용한 요청을 처리
@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);
}
}
Share