관련 포스팅
이전 포스팅에서 Spring Data Rest 에서 예외상황이 발생하면 아래 이미지 처럼 반환값이 오는 것을 볼수있었다.
하지만 클라이언트에서 이러한 상세 정보까지 알 필요가 있는가? 는 생각해봐야할 것 같다.
(원인이 상세하게 나오니 보안적으로도 좋지 않아보인다.)
이러한 Exception Message 형태를 커스텀 해보려한다.
1. @ControllerAdvice 와 @RestControllerAdvice
우선 Exception 을 감지하고, 반환 형태를 커스텀 하기 위해선 @ControllerAdivce, @RestControllerAdvice 에 대해서 짚고 넘어가려한다.
@ContollerAdvice의 설명을 보면,
@ExceptionHandler, @InitBinder 또는 @ModelAttribute 메서드를 여러 @Controller 클래스 간에 공유하도록 선언하는 클래스에 대한 @Component 라고 정의 되어 있습니다.
우리는 여기서 @ExceptionHandler 에 대한 부분이 필요하니 자세한 설명은 생략하겠습니다.
그러면 @RestControllerAdvice 와는 어떤 차이가 있나? 라는 의문이 들었습니다.
두가지 Interface 를 살펴보면,
@ContollerAdvice 는 Component 로 정의 되어 있고,
이를 @RestControllerAdvice 가 @ControllerAdvice 와 @ResponseBody 와 함께 가져와 사용하는 것을 볼 수 있습니다.
요약하자면,
@RestControllerAdvice = @ControllerAdvice + @ResponseBody 라고 보면 될것 같은데요.
두 Annotation의 차이를 보면 객체 리턴 처리가 되냐 안되냐 이다.
예시로 Response.getBody() 를 리턴값으로 하였을때를 보면,
@ControllerAdivce
* Code
* Response
@RestContorllerAdvice
* Code
* Response
Response 차이를 보면 @ControllerAdvice 는 404, @RestControllerAdvice 는 미리 정의한 409 status 로 오는 것을 볼 수 있다.
위에서 언급했다시피 @RestContollerAdvice 는 @ResponseBody 를 함께 사용하기 때문에 객체 형태로만으로도 사용이 가능하다.
2. 구현
서론이 길긴 했지만...
이제부터 코드 구현!
a. 코드
먼저, Error Code 들을 담을 Enum Class를 만들어 줍니다.
* ErrorCode.java
@Getter
public enum ErrorCode {
/* 400 BAD_REQUEST : 잘못된 요청 */
INVALID_REFRESH_TOKEN(BAD_REQUEST, "리프레시 토큰이 유효하지 않습니다"),
MISMATCH_REFRESH_TOKEN(BAD_REQUEST, "리프레시 토큰의 유저 정보가 일치하지 않습니다"),
...
/* 409 CONFLICT : Resource 의 현재 상태와 충돌. 보통 중복된 데이터 존재 */
DUPLICATE_RESOURCE(CONFLICT, "데이터가 이미 존재합니다");
private final HttpStatus httpStatus;
private final String detail;
ErrorCode(HttpStatus httpStatus, String detail) {
this.httpStatus = httpStatus;
this.detail = detail;
}
public ErrorResponse convertErrorResponse(Exception ex) {
return ErrorResponse.create(ex,httpStatus,detail);
}
}
* HttpStatus : 해당 에러에 대한 상태 코드(ex, 400)
* detail : 에러에 대한 설명 문구
* convertErrorResponse : ErrorResponse 를 만들어 반환 해주기 위한 메소드
다음으로 Exception 감지 및 반환 형태 변환을 위한 Handler 용 클래스를 만들어 줍니다.
* GlobalExceptionHandler.java
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
// @ExceptionHandler 에 ConstraintViolationException 와 DataIntegrityViolationException 만 처리하겠다. 라는 의미
@ExceptionHandler(value = { ConstraintViolationException.class, DataIntegrityViolationException.class})
protected ErrorResponse handleDataException(Exception ex) {
log.error("handleDataException throw Exception : {}", DUPLICATE_RESOURCE);
return DUPLICATE_RESOURCE.convertErrorResponse(ex);
}
}
* ControllerAdvice : ExceptionHandler 공유를 위한 어노테이션
* ExceptionHandler : 특정 Exception 을 감지하여 해당 메소드를 실행하도록 함
* DUPLICATE_RESOURCE : 미리 정의한 ErrorCode Enum Class
3. 마무리
ExceptionHandler에 정의된 예외를 발생 시키면 커스텀한 반환 형태를 얻을 수 있다.
코드는 정말 간단하게 구성했지만, Simple is best!
다른 글들을 보면 추가적으로 원하는 커스텀 방식을 볼 수 있으니 검색해보면 좋을 듯하다.
(필자도 ErrorCode 는 다른 분 글에서 따와서 넣었다.)
* git 링크
GitHub - mk1-p/spring-data-rest: Test for Spring Data Rest
Test for Spring Data Rest. Contribute to mk1-p/spring-data-rest development by creating an account on GitHub.
github.com
3. 참고문서
[Spring] 전역 예외 처리를 위한 @ControllerAdvice와 @RestControllerAdvice
목표 전역 예외처리를 위한 @ControllerAdvice와 @RestControllerAdvice에 대해서 알아보겠습니다. 개요 진행하던 프로젝트에서 리팩토링이 시급한 부분은 전체적인 구조였습니다. 복잡하고 가독성 떨어지
chanos.tistory.com
Spring Exception Handling
1. Java Exception Java 에는 Checked Exception 과 Unchecked Exception 이 존재합니다. 이 둘은 헷갈리기 쉽지만 사실 큰 차이가 존재합니다. Checked Unchecked 예외 처리 필수 필수 아님 트랜잭션 롤백 안됨 기본값
bcp0109.tistory.com
ControllerAdvice (Spring Framework 6.0.10 API)
Specialization of @Component for classes that declare @ExceptionHandler, @InitBinder, or @ModelAttribute methods to be shared across multiple @Controller classes. Classes annotated with @ControllerAdvice can be declared explicitly as Spring beans or auto-d
docs.spring.io
Exceptions :: Spring Framework
If an exception remains unresolved by any HandlerExceptionResolver and is, therefore, left to propagate or if the response status is set to an error status (that is, 4xx, 5xx), Servlet containers can render a default error page in HTML. To customize the de
docs.spring.io
'DEV > Spring' 카테고리의 다른 글
[Spring] 간편로그인 구현하기 (feat. 구글, 카카오) (0) | 2023.07.28 |
---|---|
[Spring] Spring Security 란? (0) | 2023.07.26 |
[Spring] Spring Data Rest 란? (0) | 2023.07.10 |
[JPA] Repository 인터페이스 (0) | 2023.04.19 |
[Spring] Spring Framework 란? (0) | 2023.03.31 |