1.목적
팀 프로젝트를 하면서 공지사항에 접근권한이나 잘못된 요청에대한 예외처리를 하기 위해 학습하게 되었다.
2. 학습내용
@ExceptionHandler
- @ControllerAdvice나 @RestControllerAdvice가 있는 클래스의 메소드에 사용된다.
- 매우 유연하게 에러처리를 할 수 있는 방법을 제공한다.
- 에러 응답을 자유롭게 다룰 수 있다.
@RestControllerAdvice
- Spring 4.3부터 제공하는 애노테이션이다.
- @ExceptionHandler를 전역적으로 적용할 수 있게 해준다.
- @ControllerAdvice 와의 차이점은 에러 응답을 JSON으로 내려준다는 것이다.
- 애노테이션을 적용해 전역적으로 에러를 핸들링하는 Class를 만들어 사용한다.
- 400 Bad Request: 요청이 서버에서 이해할 수 없거나 잘못된 구문으로 작성되었을 때 발생한다. 이는 올바른 요청 형식을 따르지 않은 경우에 발생한다.
- 401 Unauthorized: 요청이 인증되지 않았거나 인증이 실패했을 때 발생한다. 클라이언트가 인증되지 않은 자원에 액세스하려고 시도한 경우에 발생할 수 있다.
- 403 Forbidden: 요청이 서버에서 거부되었을 때 발생한다. 클라이언트가 요청한 자원에 액세스할 권한이 없는 경우에 발생한다.
- 404 Not Found: 요청한 리소스가 서버에서 찾을 수 없을 때 발생한다. 클라이언트가 존재하지 않는 자원에 액세스하려고 시도한 경우에 발생한다.
- 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클래스에 적용해보도록 하겠다.