[Spring]스프링에서 공통 Response처리 하기(@ControllerAdvice 이용하기)
스프링 프로젝트를 진행하다 보면 응답값 response에 대하여 공통적인 처리를 해야할 때가 있다.
필자의 경우 처음에는 interceptor의 postHandle쪽에서 다루어 보려고 했으나
인터셉터에서 접근 가능한 response에서는 클라이언트에게 반환될 body의 데이터에 접근할 수 없었다.
때문에 다른 방법을 찾다가 @ControllerAdvice라는 좋은 방법을 찾게되어 소개한다.
먼저 ControllerAdvice를 구현한 예제이다.
구현 자체는 간단하다.
@ControllerAdvice
@org.springframework.web.bind.annotation.RestControllerAdvice
public class RestControllerAdvice<T> implements ResponseBodyAdvice<T> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public T beforeBodyWrite(T body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
// 작업할 내용 작성...
return body;
}
}
1. @ControllerAdvice 및 ResponseBodyAdvice를 구현
먼저 Advice클래스로 만들 클래스에 어노테이션 @ControllerAdvice를 붙여준 뒤
(필자의 경우 API서버였기 때문에 @RestControllerAdvice를 붙여주었다)
ResponseBodyAdvice의 구현체로 만들어준다.
2. supports와 beforeBodyWrite을 오버라이딩
ResponseBodyAdvice를 구현하기 위해 두 메소드(supports, beforeBodyWrite)를 오버라이딩 해야한다.
이 두 메소드의 역할은
supports에서 현재 Controller작업이 끝난 response를 beforeBodyWrite로 보낼 것인지 판단 한 뒤
보내게 되면 beforeBodyWrite에서 사용자가 원하는 작업을 하도록 하는 구조이다.
3. supports의 기능
supports의 인터페이스로 가서 보면 다음과 같이 기술되어있다.
/**
* Whether this component supports the given controller method return type
* and the selected {@code HttpMessageConverter} type.
* @param returnType the return type
* @param converterType the selected converter type
* @return {@code true} if {@link #beforeBodyWrite} should be invoked;
* {@code false} otherwise
*/
boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType);
따라서 여기서 작업을 해야하는 response인지 판단해서 boolean값으로 리턴해주면 된다.
참고로 필자의 경우 이 요청이 어느 컨트롤러에서 왔는지 판별해서 작업 필요여부를 판단하였는데
아래와 같이 하면 request가 어느 컨트롤러 클래스에서 왔는지 알아낼 수 있다.
returnType.getExecutable().getDeclaringClass()
4. beforeBodyWrite의 기능
이 메소드의 인터페이스로 올라가보면 아래와 같이 기술되어있다.
/**
* Invoked after an {@code HttpMessageConverter} is selected and just before
* its write method is invoked.
* @param body the body to be written
* @param returnType the return type of the controller method
* @param selectedContentType the content type selected through content negotiation
* @param selectedConverterType the converter type selected to write to the response
* @param request the current request
* @param response the current response
* @return the body that was passed in or a modified (possibly new) instance
*/
@Nullable
T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response);
필자가 이해한 내용에 따르면
Controller응답이 끝난 뒤 반환된 Body데이터를 json이나 xml등의 기타 형식으로 변환할 HttpMessageConverter가 선택되었지만 데이터를 변환하기 직전에 호출이 된다는 내용으로 보인다.
즉, 클라이언트와 json형식으로 주고받는 api서버인 상황이라고 가정해 보았을 때
HttpMessageConverter로 json 변환 클래스가 선택이 된 상황이고
반환된 body의 데이터들을 선택된 converter를 이용하여 json으로 바꾸기 직전에 호출되는 것이다.
만약 공통적으로 이 body 데이터를 검사해서 특정 값을 바꿔치기하고 싶다면 여기서 하면 된다.
그리고 body의 값을 반환해주면 반환된 데이터로 json으로 바뀌어 클라이언트에게 전달된다고 보면 된다.
'Backend > Spring' 카테고리의 다른 글
[Spring]프로토 타입 빈 사용시 생기는 문제점 해결하기(ObjectProvider와 JSR-330 Provider) (0) | 2020.11.12 |
---|---|
[Spring]싱글톤 빈 VS 프로토 타입 빈 차이점 (0) | 2020.11.11 |
ipTIME의 DDNS를 이용하여 운영 서버 구축하기(포트포워딩) (1) | 2020.10.30 |
[Spring]빈 스코프(Bean Scope)의 종류 및 개념 (0) | 2020.10.27 |
[Spring]스프링 빈(Bean)을 초기화 및 종료하는 3가지 방법(Bean 생명주기 콜백) (0) | 2020.10.27 |