Spring Boot 내부에서 발생하는 예외를 전담해서 처리하는 Handler를 지정하면 예외 발생시 Response Message를 일괄 처리할 수 있습니다. 다음과 같이 @ControllerAdvice
를 지정하여 예외 처리를 전담하는 Exception Handler를 정의합니다. 그리고 @ExceptionHandler
를 통해 처리하고자 하는 Exception을 등록하고 처리하는 로직을 작성합니다.
import org.springframework.data.rest.core.RepositoryConstraintViolationException; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.ObjectError; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import java.util.stream.Collectors; @ControllerAdvice public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler { @ExceptionHandler({RepositoryConstraintViolationException.class}) public ResponseEntity<Object> handleAccessDeniedException(Exception ex, WebRequest request) { RepositoryConstraintViolationException nevEx = (RepositoryConstraintViolationException) ex; String errors = nevEx.getErrors().getAllErrors().stream().map(ObjectError::toString).collect(Collectors.joining("\n")); return new ResponseEntity<>(errors, new HttpHeaders(), HttpStatus.NOT_ACCEPTABLE); } }
REST의 경우 @RestControllerAdvice
를 이용하면 되며 사용방법은 동일합니다.
@RestControllerAdvice public class ExceptionAdvice { @ExceptionHandler(value = NotFoundException.class) public ResponseEntity<CustomErrorResponse> handleGenericNotFoundException(NotFoundException e) { CustomErrorResponse error = new CustomErrorResponse("NOT_FOUND_ERROR", e.getMessage()); error.setTimestamp(LocalDateTime.now()); error.setStatus((HttpStatus.NOT_FOUND.value())); return new ResponseEntity<>(error, HttpStatus.NOT_FOUND); } }
이렇게 작성한 REST 컨트롤러용 Global Exception Handler는 예외 발생시 다음과 같이 메시지를 전달합니다.
{ "errorCode": "NOT_FOUND_ERROR", "errorMsg": "Customer not found with id 1", "status": 404, "timestamp": "2019-12-26 11:45:59" }
Exception에 Response Status를 매핑하여 Exception 별로 HTTP Status Code와 매핑하고 싶은 경우 다음과 같이 코드를 작성할 수 있습니다.
import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(HttpStatus.NOT_FOUND) public class DogsNotFoundException extends RuntimeException { public DogsNotFoundException(String message) { super(message); } }
또한 예외에 따라서 간단하게 HTTP Status Code로 리턴을 하고 싶다면 아래와 같이 Exception Handler에 @ResponseStatus
를 붙이면 됩니다.
import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; @ControllerAdvice public class DogsServiceErrorAdvice { @ResponseStatus(HttpStatus.NOT_FOUND) @ExceptionHandler({DogsNotFoundException.class}) public void handle(DogsNotFoundException e) {} @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler({DogsServiceException.class, SQLException.class, NullPointerException.class}) public void handle() {} @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler({DogsServiceValidationException.class}) public void handle(DogsServiceValidationException e) {} }
보다 상세한 사항은 https://dzone.com/articles/spring-rest-service-exception-handling-1을 참고하십시오.