문홍의 공부장

[Spring] ResponseBodyAdvice 를 이용하여 ControllerAdvice 활용하기 본문

개발/Spring

[Spring] ResponseBodyAdvice 를 이용하여 ControllerAdvice 활용하기

moonong 2024. 1. 24. 22:35
반응형

 

공통 응답 형식을 만들 때, 이전에는 컨트롤러 단에서 ResponseDto 를 객체를 이용하여 응답값을 필드에 set 하여 내려주었다.
이 경우, 모든 API 에 ResponseDto 를 직접 적어주어야 한다. 누락되는 케이스가 존재할 수 있고, 공통되는 영역이니 한 곳에서 관리하고자 하는 욕구가 생긴다.

 

스프링에서 제공하는 ResponseBodyAdvice 인터페이스를 이용하여 공통 응답 형식을 만들 수 있다.

 

public interface ResponseBodyAdvice<T> {  
    boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType);  

    @Nullable  
    T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response);  
}

 

 

 

supports() 메서드는 controller 작업이 끝난 response를 beforeBodyWrite 메서드에 보낼지 판단한다. 컨트롤러의 returnType, messageConverter 정보를 이용하여 beforeBodyWrite() 로 보낼지 여부를 결정한다.

 

beforeBodyWrite() 메서드는, controller 작업이 끝나고 어떠한 Converter를 통해 응답을 보낼지 결정된 후에 호출된다. 이 메서드를 구현할 때 실제 원하는 바디 형식 또는 헤더 정보 등을 추가하여 커스터마이징 할 수 있다.

 

ResponseBodyAdvice 인터페이스를 구현한 클래스에 @ControllerAdvice 어노테이션을 추가하여 스프링 빈으로 등록한다. 이를 통해 스프링부트 애플리케이션 전역에서 핸들링 할 수 있도록 한다.

 

 

@Slf4j  
@ControllerAdvice(basePackages = "com.sample")
public class ResponseAdvice implements ResponseBodyAdvice {  
    @Override 
    public boolean supports(MethodParameter returnType, Class converterType) {
    	return !returnType.getParameterType().equals(ResponseWrapper.class);
    }

    @Override  
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {  
        if (body == null) {  
            return null;  
        }  
        return new ResponseWrapper(response, body);  
    }

 

 

swagger 의 값은 공통 응답 형식을 적용하지 않도록 basePackages 설정을 추가하고, ResponseBodyAdvice 인터페이스를 구현한다. beforeBodyWrite() 를 오버라이드하여 응답 바디를 쓰기 전에 공통 응답 Wrapper 로 감싸 응답을 내려줄 수 있도록 한다.

 

 

public class ResponseWrapper {  
    private Integer status;  
    private String message;  
    private Object data;        // 결과 데이터  

    public ResponseWrapper() {  
        HttpStatus httpStatus = HttpStatus.OK;
        status = httpStatus.value();  
        message = httpStatus.getReasonPhrase();  
    }

    public ResponseWrapper(ServerHttpResponse response, Object body) {  
        HttpStatus httpStatus = HttpStatus.OK;
        status = httpStatus.value();  
        message = httpStatus.getReasonPhrase();   
        data = body;  
    }
}
반응형