스프링 부트를 사용하면서 컨트롤러에서 발생하는 예외를 처리하는 방법을 알아보자
@ExceptionHandler
@ControllerAdvice
컨트롤러에서 발생하는 예외를 매번 try catch문으로 감싸면 난리난다~
공통로직, 반복적인것을 계속해야 하니까 엄청 귀찮아진다. 그럴때 쓰라는게 AOP이다.
먼저 커스텀하게 NotFoundException 클래스를 생성하자.
주로 런타임 중 발생하는 예외를 처리해야하는 경우가 많기 때문에 RuntimeException을 상속받고, code라는 멤버 변수를 필드로 가지고 있는다.
NotFoundException.java
public class NotFoundException extends RuntimeException {
public final static int INDEX_NOT_FOUND = 101;
public final static int BOARD_NOT_FOUND = 201;
private final int code;
public int getCode() {
return code;
}
public NotFoundException(int code) {
this.code = code;
}
public NotFoundException(int code, String message) {
super(message);
this.code = code;
}
}
ErrorCode.java
public enum ErrorCode {
INDEX_NOT_FOUND(1001, "인덱스가 존재하지 않습니다."),
BOARD_NOT_FOUND(1002, "게시글을 찾을 수 없습니다.");
private int errorCode;
private String errorMessage;
public String getErrorMessage() {
return errorMessage;
}
public int getErrorCode() {
return errorCode;
}
ErrorCode(int errorCode, String errorMessage) {
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}
}
에러코드를 Enum으로 관리하여 필요한 에러코드를 뽑아서 사용할 수 있도록 만들었다.
이렇게 하면 좀 더 체계적으로 에러코들르 관리할 수 있을 것 같다.
IndexController.java
@GetMapping("/exception-test")
public ResponseEntity notFound() {
throw new NotFoundException(ErrorCode.INDEX_NOT_FOUND.getErrorCode(), ErrorCode.INDEX_NOT_FOUND.getErrorMessage());
}
@ExceptionHandler(NotFoundException.class)
public ResponseEntity<ErrorResult> notFoundException(NotFoundException e) {
ErrorResult er = new ErrorResult();
er.setCode(e.getCode());
er.setStatus(HttpStatus.NOT_FOUND);
er.setMessage(e.getMessage());
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(er);
}
/exception-test
라는 엔드포인트를 가진 API를 만들고 NotFoundException
을 발생시킨다. 그 때 위에서 만든 ErrorCode
Enum 클래스에서 에러코드와 에러메시지를 받아서 넣어준다.ExceptionHandler
어노테이션을 가진 메서드를 만든다.notfound()
에서 NotFoundException
예외를 처리한다./exception-test
를 실행시켜보면 아래와 같이 NotFoundException
을 처리한다.모든 클래스에서 메서드마다 발생하는 발생하는 @ExceptionHandler
를 중복해서 만들어야 할까?
여러 클래스에서 터진 Exception
들을 처리할 수 있는 @ControllerAdivce
를 어노테이션으로 가지는 클래스를 만들어보자.
@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);
}
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
HttpHeaders headers,
HttpStatus status,
WebRequest request) {
ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(),
"Validation Failed", ex.getBindingResult().toString());
return new ResponseEntity(exceptionResponse, HttpStatus.BAD_REQUEST);
}
}