페이지 수정은 작성 후 24시간 안에만 가능하도록 하기 위해서,
작성 후 24시간이 경과하였는지 확인하는 메소드를 작성하였다.
만약 24시간이 경과하였다면 exception을 발생시켜 사용자에게 알린다.
여기서 발생한 예외를 처리하는 방법이 나뉜다.
Spring은 기본적으로 예외를 처리하는 BasicErrorController를 구현해두었다.
별도의 예외를 처리하지 않으면, WAS까지 error가 전달된다.
그리고 WAS는 다시 BasicErrorController로 다시 에러에 대한 처리를 요청한다.
WAS(톰캣) -> 필터 -> 서블릿(디스패처 서블릿) -> 인터셉터 -> 컨트롤러
-> 컨트롤러(예외발생) -> 인터셉터 -> 서블릿(디스패처 서블릿) -> 필터 -> WAS(톰캣)
-> WAS(톰캣) -> 필터 -> 서블릿(디스패처 서블릿) -> 인터셉터 -> 컨트롤러(BasicErrorController)
이 방식의 문제점은 Error에 대한 구체적인 정의를 할 수 없다는 것,
Error처리를 위해 한 번 더 요청을 해야한다는 점이다.
4가지 방법 중 가장 좋은 방식이다.
기본 Error처리의 단점을 보완하고, Error처리를 보다 체계적으로 할 수 있도록 기능을 제공한다.
@ExceptionHandler 어노테이션을 추가함으로써, 특정 error에 대한 처리를 할 수 있다.
@ExceptionHandler(NoSuchElementFoundException.class)
public ResponseEntity<String> handleNoSuchElementFoundException(NoSuchElementFoundException exception) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(exception.getMessage());
}
Exception이 발생하면 해당 exception에 대한 정보를 설정하여 ResponseEntity에 담아 클라이언트에게 전달할 수 있다.
즉, ErrorCode와 message에 대한 정보를 직접 설정하여 전달함으로써 Error발생에 대한 구체적인 정보를 제공한다.
각 Controller에서 예외를 처리한다면, 중복 코드가 발생한다.
이를 개선하기 위해 하나의 컨트롤러에 @RestControllerAdvice 어노테이션을 추가하여 여러 컨트롤러에 전역적으로 ExceptionHandler를 적용한다.
package com.project.only.error;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(RestApiException.class)
public ResponseEntity<Object> handleCustomException(RestApiException e) {
ErrorCode errorCode = e.getErrorCode();
return handleExceptionInternal(errorCode);
}
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<Object> handleIllegalArgument(IllegalArgumentException e) {
log.warn("handleIllegalArgument", e);
ErrorCode errorCode = CommonErrorCode.INVALID_PARAMETER;
return handleExceptionInternal(errorCode);
}
@ExceptionHandler({Exception.class})
public ResponseEntity<Object> handleAllException(Exception ex) {
log.warn("handleAllException", ex);
ErrorCode errorCode = CommonErrorCode.INTERNAL_SERVER_ERROR;
return handleExceptionInternal(errorCode);
}
private ResponseEntity<Object> handleExceptionInternal(ErrorCode errorCode) {
return ResponseEntity.status(errorCode.getHttpStatus())
.body(makeErrorResponse(errorCode));
}
private ErrorResponse makeErrorResponse(ErrorCode errorCode) {
return ErrorResponse.builder()
.code(errorCode.name())
.message(errorCode.getMessage())
.build();
}
}
이런식으로 ControllerAdvice를 이용함으로써