본문 바로가기

Spring/Springboot

📝 스프링(Spring) 예외(Exception)처리 1

 

1. 에러(Error)와 예외(Exception)

1) 에러(Error) - java.lang.error 클래스

처리할 수 없는 심각한 오류를 나타내는 클래스로 throw가 되었지만 catch되지 않은 것으로

오류는 개발자가 처리 할 수 없는 경우로 메모리 에러, 스택 오버 플로우 같은 시스템 비정상의 상황으로 주로 JVM에서 발생

시스템 레벨에서 특별한 작업을 하는 것이 아닌 이상 에러 처리를 하지 않아도 됨

 

2) 예외(Exception) - java.lang.exception 클래스

프로그램이 복구할 수 있고 응용 프로그램에서 개발자가 처리해야 하는 문제

  Unchecked Exception(RunTimeException:) Checked Exception
예외처리 - 컴파일 타임에 확인할 수 없는 예외
- 개발자는 Unchecked Exception을 발견하거나 예상이 된다면 해당 예외에 대한 처리를 해야 함 -> 선택
(예측할 수 없는 예외이기 때문에 필수 처리 불가)
- 컴파일 타임에 확인할 수 있는 예외
- 개발자는 이러한 예외에 대한 처리를 해야 함 -> 필수
트랜잭션  롤백 O X
롤백 처리를 하려면 트랜잭션 설정 필요
발생/검증 런타임(실행) 단계 컴파일 단계

 

 

2. 예외 처리 방법

1) 예외 복구: 예외 상황을 파악하고 문제를 해결하여 정상 상태로 복구하는 것

ex. 해결을 위한 작업 처리 흐름에 대한 메시지, 네트워크 관련 에러라면 재시도 또는 일정 시간 대기

 

2) 예외 처리 회피: 예외 발생 시 직접 처리하지 않고 자신을 호출한 메소드로 예외를 던짐(thorws)

 

3) 예외 전환: 예외를 적절한 예외로 전환하여 메소드 밖으로 던짐 (thorws), 예외 처리 회피와 다른점은 적절한 예외로 전환한다는 것

적절한 예외 ex

1. 의미 있고 추상화된 예외로 전환: 중복된 아이디를 입력하면 실제로 SQLException이 발생함 하지만SQLException라고하면 구체적인 에러 발생 원인 파악이 어려움, DuplicatedUserIdExeption 같이 예외를 구체적으로 바꿔서 throws

 

2. 런타임 예외로 wrap하여 전환: checkedException인데 복구가 불가능한 에러는 불필요한 예외 처리를 하지 않고 런타임 에러로 감싸서 전환하는 형태, 예외 상황을 구체적으로 로그로 보여줌, 관리자 문의 페이지로 넘김

 

 

 

3.  예외(Exception ) 처리 범위에 따른 분류

1) 메서드(Method Level using)

- try~catch를 사용하여 예외 처리

- 예외 발생시 로직의 흐름을 끊어야 하는데, 예외가 발생해도 다음 로직 실행하므로 try~catch 처리를 지양해야함

- Checked Exception 같은 경우에는 예외를 반드시 감싸야 하므로(예외처리 필수)이러한 경우에 사용

- try~catch는 반드시 적절한 조치를 취해야함 

 

2) 컨트롤러(Controller Level using) 

- @ExceptionHandler를 사용하여 예외 처리: 특정 Controller에 적용시켜서 에러가 발생했을 때 Catch 될 수 있게 해주는 것

- @valid 어노테이션을 사용하여 예외를 잡고 @ControllerAdvice에서 핸들링

 

3) 전역(Global Level using)

- @ControllerAdvice 또는 @RestControllerAdvice와  @ExceptionHandler를 사용하여 예외처리

- AOP(Aspect Oriented Programming)의 예로 볼 수 있음

- 서비스, 컨트롤러에서 Exception을 thorws 하고, 전역 예외 클래스로 일괄 처리

 

cf) @ControllerAdvice 또는 @RestControllerAdvice 차이: @RestControllerAdvice는 자바 객체를 Json/Xml 형태로 반환하여 HTTP Response Body담아 보낼 수 있음

 

 

4. 전역 예외(Global Exception) 처리 코드 구현 하기

1) ErrorCode: Enum 클래스로 생성, 예외 케이스를 처리할 에러 코드 관리

에러코드는 하나의 클래스로 관리하여 메시지 중복 방지, 통일성 있는 예외 처리를 위함

 

2) ErrorResponse: 예외 발생 시 응답 클래스, 예외 처리 정보가 들어감, JSON형식으로 에러 응답을 공통적이게 보내 줌

- ErrorResponse로 응답해야하는 이유: 예외를 동일한 로직으로 처리하기 위해 -> 왜? 에러의 구체적 원인을 알려주기 위해

  • message : 에러에 대한 메시지 작성
  • status : http status code, header 정보에 포함된 정보라서 선택 사항
  • errors : @Valid 어노테이션으로 JSR 303: Bean Validation에 대한 검증을 요청 값에 대한 검증한 결과를 응답, MethodArgumentNotValidException의 getBindingResult에서 값을 가져와서 작성(바인딩 결과 없을 시 @JsonInclude를 넣어 응답하지 않도록 함)
속성 설명
@JsonInclude(JsonInclude.Include.ALWAYS) 모든 데이터를 JSON으로 변환
@JsonInclude(JsonInclude.Include.NON_NULL) 값이 NULL인 데이터 제외
@JsonInclude(JsonInclude.Include.ALWAYS.NON_ABSENT) - 값이 NULL인 데이터 제외
- 참조 유형 absent 제외
@JsonInclude(JsonInclude.Include.NON_EMPTY) - 값이 NULL인 데이터 제외
- 참조 유형 absent 제외
- Collections, Map의 IisEmpty()가 true인 데이터 제외
- Array의 length가 0인 데이터 제외
- String의 length가 0인 데이터 제외 
@JsonInclude(JsonInclude.Include.NON_DEFAULT) - 값이 empty인 데이터 제외
- 기본형 타입이 default값인 데이터 제외
- Date의 timestamp가 0L인 데이터 제외
  • code : 에러에 할당되는 유니크한 코드값

3) CustomException 또는 BusiniessException: RuntimeException 상속 받는 사용자 정의 예외 클래스

- @RestControllerAdvice(@ControllerAdvice)

- @ExceptionHandler로 에러 발생 시 각각의 예외 처리, @ExceptionHandler(????Exception.class)형식

- 주요 @ExceptionHandler 

handleMethodArgumentNotValidException - @Valid, @Validated 으로 binding error 발생
- HttpMessageConverter에서 등록한 binding 실패 시 
handleBindException - @ModelAttribute 으로 binding error 발생 시 BindException 발생
MethodArgumentTypeMismatchException - enum type 일치하지 않아 binding 못 할 경우 발생
- 주로 @RequestParam enum으로 binding 못했을 경우 발생
handleHttpRequestMethodNotSupportedException - 지원하지 않은 HTTP method 호출 할 경우 발생
handleAccessDeniedException - Authentication 객체가 필요한 권한을 보유하지 않은 경우 발생
- Security에서 던지는 예외
handleException - 그 밖에 발생하는 모든 예외 처리
- 개발자가 직접 핸들링해서 다른 예외로 던지지 않을 시
handleBusinessException 비즈니스 요구사항에 따른 Exception