Spring 에서 Exception 처리를 위한 방법에 대해 알아보자.
기본적으로 Spring 에서는 Exception 을 처리하기 위해 @ControllerAdvice
를 사용한다.
현재는 @RestControllerAdvice
를 사용하는 것이 더욱 편리하다. 아무래도 React + Spring 을 사용하는 경우가 많기 때문이다.
서버와 클라이언트가 분리되어 있기 때문에, 서버에서는 @RestControllerAdvice
를 사용하는 예제로 알아보자.
@RestControllerAdvice
는 @ControllerAdvice
와 동일한 기능을 하지만, @ResponseBody
가 추가되어 있다.
@ResponseBody
이것은 Json 형태로 응답을 보내기 위한 어노테이션이다.
@RestControllerAdvice
를 사용하면, @ExceptionHandler
를 사용하여 Exception 을 처리할 수 있다.
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = {Exception.class})
public ResponseEntity<ErrorResponse> handleException(Exception e) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setMessage(e.getMessage());
errorResponse.setCode("EXCEPTION");
return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@RestControllerAdvice
어노테이션을 사용하면 전역적으로 에러를 관리 할 수 있다.
{
"code": "EXCEPTION",
"message": "test"
}
위와 같이 Error Message 를 custom 할 수 있기 때문에 Client 에서 에러를 처리하기가 편리하다.
@ExceptionHandler
는 @ControllerAdvice
에서 사용할 수 있는 어노테이션이다.
@ExceptionHandler
를 사용하면, 특정 Exception 을 처리할 수 있다.
enum Type 으로 Custom Exception 을 만들어서 사용할 수 있다.
public enum ErrorCode {
INVALID_INPUT_VALUE(400, "C001", " Invalid Input Value"),
METHOD_NOT_ALLOWED(405, "C002", " Invalid Input Value"),
HANDLE_ACCESS_DENIED(403, "C003", "Access is Denied"),
INTERNAL_SERVER_ERROR(500, "C004", "Server Error"),
ENTITY_NOT_FOUND(400, "C005", "Entity Not Found");
private final String code;
private final String message;
private final int status;
ErrorCode(final int status, final String code, final String message) {
this.status = status;
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
public String getMessage() {
return message;
}
public int getStatus() {
return status;
}
}
public class CustomException extends RuntimeException {
private ErrorCode errorCode;
public CustomException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.errorCode = errorCode;
}
public ErrorCode getErrorCode() {
return errorCode;
}
}
Runtime Exception
을 상속받아서 Custom Exception 을 만들 수 있다.
Enum Class 에서 정의한 error code 와 Message를 exception 때 넘겨 줄 수 있다.
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = {CustomException.class})
public ResponseEntity<ErrorResponse> handleCustomException(CustomException e) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setMessage(e.getErrorCode().getMessage());
errorResponse.setCode(e.getErrorCode().getCode());
return new ResponseEntity<>(errorResponse, HttpStatus.valueOf(e.getErrorCode().getStatus()));
}
}
위는 이제 커스텀한 Exception 을 처리하는 예제이다.
보면 알겠지만 @ExceptionHandler
에서 CustomException.class
를 넘겨주면, CustomException
을 처리할 수 있다.
@RestController
public class TestController {
@GetMapping("/test")
public String test() {
throw new CustomException(ErrorCode.ENTITY_NOT_FOUND);
}
}
{
"code": "C005",
"message": "Entity Not Found"
}
Json 응답이 잘 나오는 것을 확인 할 수 있다.
일반적으로 Http Status 가 동적으로 변할 수 있는 경우 ResponseEntity
를 사용하고, Http Status 가 정적인 경우 ResponseEntity
를 사용하지 않는다.
정적인 경우에는 @ResponseStatus
를 사용하면 된다.
@ExceptionHandler(value = {NullPointerException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleNullPointerException(NullPointerException e) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setMessage(e.getMessage());
errorResponse.setCode("NULL_POINTER_EXCEPTION");
return errorResponse;
}
위 같은 경우는 ErrorResponse를 바로 Return 해주었고 Http Status 를 400으로 설정해주었다.
끝!