본문 바로가기

카테고리 없음

[예외처리]@ExceptionHandler,@RestControllerAdvice

1.목적

팀 프로젝트를 하면서 공지사항에 접근권한이나 잘못된 요청에대한 예외처리를 하기 위해 학습하게 되었다.

2. 학습내용

@ExceptionHandler

  • @ControllerAdvice나 @RestControllerAdvice가 있는 클래스의 메소드에 사용된다.
  • 매우 유연하게 에러처리를 할 수 있는 방법을 제공한다.
  • 에러 응답을 자유롭게 다룰 수 있다.

@RestControllerAdvice

  • Spring 4.3부터 제공하는 애노테이션이다.
  • @ExceptionHandler를 전역적으로 적용할 수 있게 해준다.
  • @ControllerAdvice 와의 차이점은 에러 응답을 JSON으로 내려준다는 것이다.
  • 애노테이션을 적용해 전역적으로 에러를 핸들링하는 Class를 만들어 사용한다.
  1. 400 Bad Request: 요청이 서버에서 이해할 수 없거나 잘못된 구문으로 작성되었을 때 발생한다. 이는 올바른 요청 형식을 따르지 않은 경우에 발생한다.
  2. 401 Unauthorized: 요청이 인증되지 않았거나 인증이 실패했을 때 발생한다. 클라이언트가 인증되지 않은 자원에 액세스하려고 시도한 경우에 발생할 수 있다.
  3. 403 Forbidden: 요청이 서버에서 거부되었을 때 발생한다. 클라이언트가 요청한 자원에 액세스할 권한이 없는 경우에 발생한다.
  4. 404 Not Found: 요청한 리소스가 서버에서 찾을 수 없을 때 발생한다. 클라이언트가 존재하지 않는 자원에 액세스하려고 시도한 경우에 발생한다.
  5. 405 Method Not Allowed: 클라이언트가 요청한 HTTP 메서드가 서버에서 허용되지 않을 때 발생한다. 예를 들어, GET 요청을 허용하지 않는 리소스에 대해 GET 요청을 시도한 경우에 발생한다.

3.사용 코드

@RestControllerAdvice
public class NoticeExceptionHandler {

    @ExceptionHandler(NoticeNotFoundException.class) // 404 Not Found
    public ResponseEntity<ErrorResponse> handleNoticeNotFoundException(NoticeNotFoundException ex) {
        ErrorResponse response = ErrorResponse.from(HttpStatus.NOT_FOUND, "Notice Not Found", 404, ex.getMessage());
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
    }

    @ExceptionHandler(InvalidNoticeRequestException.class) // 400 Bad Request
    public ResponseEntity<ErrorResponse> handleInvalidNoticeRequestException(InvalidNoticeRequestException ex) {
        ErrorResponse response = ErrorResponse.from(HttpStatus.BAD_REQUEST, "Invalid Notice Request", 400, ex.getMessage());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
    }

    @ExceptionHandler(AccessDeniedNoticeException.class) // 403 Forbidden (권한 부족)
    public ResponseEntity<ErrorResponse> handleAccessDeniedNoticeException(AccessDeniedNoticeException ex) {
        ErrorResponse response = ErrorResponse.from(HttpStatus.FORBIDDEN, "Access Denied", 403, ex.getMessage());
        return ResponseEntity.status(HttpStatus.FORBIDDEN).body(response);
    }

    @ExceptionHandler(UnauthorizedNoticeException.class) // 401 Unauthorized (인증 오류)
    public ResponseEntity<ErrorResponse> handleUnauthorizedNoticeException(UnauthorizedNoticeException ex) {
        ErrorResponse response = ErrorResponse.from(HttpStatus.UNAUTHORIZED, "Unauthorized", 401, ex.getMessage());
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response);
    }

}

 

public class AccessDeniedNoticeException extends  RuntimeException{
    public AccessDeniedNoticeException(String message) {
        super(message); // RuntimeException 클래스의 생성자 호출 
    }
}

public class InvalidNoticeRequestException extends RuntimeException {
    public InvalidNoticeRequestException(String message) {
        super(message);
    }
}

public class NoticeNotFoundException extends RuntimeException{
    public NoticeNotFoundException(String message){
        super(message);
    }
}

public class UnauthorizedNoticeException extends RuntimeException{
    public UnauthorizedNoticeException(String message) {
        super(message);
    }
}

각각의 클래스는 RuntimeException 클래스를 상속하고 있다. RuntimeException은 일반적으로 프로그램 실행 중 발생할 수 있는 예외를 나타낸다.

 

public class ErrorResponse {
    private final HttpStatus status;
    private final String errorType;
    private final int code;
    private final String message;

    private ErrorResponse(HttpStatus status, String errorType, int code, String message) {
        this.status = status;
        this.errorType = errorType;
        this.code = code;
        this.message = message;
    }

    public static ErrorResponse from(HttpStatus status, String errorType, int code, String message) {
        return new ErrorResponse(status, errorType, code, message);
    }
}

4. 마무리

예외 처리를 위한 어노테이션과 응답클래스를 작성하였다.

다음 작업으로 필요한 예외가 적절히 던져질수 있도록 service클래스에 적용해보도록 하겠다.