[Spring] Exception 관리하기

손시연·2022년 8월 30일
0

project

목록 보기
9/11

예) 방을 삭제하는 로직에서 방을 찾을 수 없는 경우

사용 방법

1. enum ErrorCode 에 내가 만들고 싶은 에러 추가 - ROOM_NOT_FOUND_ERROR

- enum ErrorCode 에서 모든 메시지를 관리함
@Getter
@AllArgsConstructor
public enum ErrorCode {

	// Global
	INTERNAL_SERVER_ERROR(500, HttpStatus.INTERNAL_SERVER_ERROR, "내부 서버 오류입니다."),
  ...

	// Room
  ROOM_NOT_FOUND_ERROR(404, HttpStatus.NOT_FOUND, "해당 방이 존재하지 않습니다.")
  ...

	;

	private final int value;
	private final HttpStatus status;
	private final String message;

}

2. Custom Exception Class 생성

public class RoomNotFoundException extends ApiException {
	public RoomNotFoundException(ErrorCode errorCode) {
		super(errorCode);
	}
}

3. 로직에서 사용

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class RoomService {

    public void delete(Long id){
        Room deleteRoom = repository.findById(id)
			    .orElseThrow(() -> new RoomNotFoundException(ErrorCode.ROOM_NOT_FOUND_ERROR));  
        repository.delete(deleteRoom);
    }
}
  • 참고) ErrorCode.ROOM_NOT_FOUND_ERROR 는 static import 하여 ROOM_NOT_FOUND_ERROR으로 작성하는 게 가독성이 좋을 것 같습니다.

🤯상속관계와 코드를 이해해 보자!

상속관계

@Getter
public abstract class ApiException extends RuntimeException {

    private ErrorCode errorCode;

    public ApiException(ErrorCode errorCode) {
        super(errorCode.getMessage());
        this.errorCode = errorCode;
    }
}
public class RoomNotFoundException extends ApiException {

	**public RoomNotFoundException(ErrorCode errorCode) {
		super(errorCode);
	}**
}
  • 코드
    • ApiException 를 추상 클래스로 만듦
    • super(errorCode) 를 통해 부모 클래스로 값을 전달

GlobalExceptionHandler

@RestControllerAdvice
public class GlobalExceptionHandler {

	@ExceptionHandler(Exception.class)
	protected ResponseEntity<ErrorResponse> handleException(final Exception e) {
		e.printStackTrace();
		**return ResponseEntity
			.status(INTERNAL_SERVER_ERROR)
			.body(ErrorResponse.of(500, INTERNAL_SERVER_ERROR, e.getMessage()));**
	}

	@ExceptionHandler(**ApiException.class**)
	protected ResponseEntity<ErrorResponse> handleApiException(final ApiException e) {
		e.printStackTrace();
		ErrorCode errorCode = e.getErrorCode();
		**return ResponseEntity
			.status(errorCode.getStatus())
			.body(ErrorResponse.of(errorCode));
	}**
}
  • @RestControllerAdvice : @Controller나 @RestController에서 발생한 예외를 한 곳에서 관리하고 처리할 수 있게 도와주는 어노테이션

  • @ExceptionHandler : 예외 처리 상황이 발생하면 해당 Handler로 처리하겠다고 명시하는 어노테이션

  • e.printStackTrace() : 에러의 발생근원지를 찾아서 단계별로 에러를 출력

  • @ExceptionHandler(Exception.class) -> 지정하지 않은 에러들은 모두 500 에러로 발생

  • @ExceptionHandler(ApiException.class) -> enum ErrorCode 에서 작성한 정보에 따라 에러가 출력됨


Response 형태

  • ErrorResponse
    • 응답 형태를 위한 DTO
@Getter
@AllArgsConstructor
public class ErrorResponse {
	private int value;
	private HttpStatus status;
	private String message;

	public static ErrorResponse of(int value, HttpStatus status, String message) {
		return new ErrorResponse(value, status, message);
	}

	public static ErrorResponse of(ErrorCode errorCode) {
		int value = errorCode.getValue();
		HttpStatus status = errorCode.getStatus();
		String message = errorCode.getMessage();
		return new ErrorResponse(value, status, message);
	}
}
  • 출력 예시
{
"value" : "404"
"status" : "NOT_FOUND"
"message" :  "해당 방이 존재하지 않습니다."
}
profile
Server Engineer

0개의 댓글