Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

잡동사니를 모아두는 서랍장

Request Body를 따로 읽고 싶을 때 본문

Spring

Request Body를 따로 읽고 싶을 때

kingkk31 2020. 4. 21. 21:53

Request Body 인터셉터에서 읽고 싶을  2편 주의

 

꼭 인터셉터가 아니라도 body 값은 한번 읽히면 날아간다는 건 동일하다. 저번엔 필터에서 래핑하여 인터셉터에서 읽었지만 그렇게 하면 성능 이슈가 있다고 한다.

이번엔 다른 대안으로 소개받은 RequestBodyAdviceAdapter 를 사용해서 body값을 다른 곳에서 읽어보려 한다. 정확히 말하자면 body를 읽는건 여전히 한번이지만, 이 내용이 변환된 객체를 컨트롤러로 넘어가기 전에 확인하는 작업을 해보자.

 

RequestBodyAdviceAdapter RequestBodyAdvice 인터페이스를 구현한 클래스이다RequestBodyAdvice 는 

Body의 내용을 읽고 Object로 변환하기 전에 요청을 커스텀 하거나, 변환된 Object가 컨트롤러 메소드에서 @RequestBody 에 매핑될 때 이 Object로 따로 작업을 처리를 할 수 ​​있다.

@ControllerAdvice 로 어드바이스를 명시해줘야 하며, RequestBodyAdviceAdapter supports 메소드의 리턴값이 true 일 경우만 어드바이스가 적용된다(API 문서 제대로 안읽어서 이거 모르고 30분을 삽질했다...). 이 supports를 잘 이용하면 특정 상황에서만 어드바이스를 적용시킬 수도 있을거다.

 

아래는 예시 코드다((저세상 네이밍과 코드상태는 무시하자).

 

먼저 RequestBodyAdviceAdapter 를 상속하여 새로운 어드바이스 어댑터를 만들었다. supports 를 무조건 true로 리턴시켜놔서 모든 컨트롤러로 요청에 대해 매핑이 이루어질 때 어드바이스가 적용된다. 이제 요청이 들어와 body가 읽혀 변환이 일어나기 전후로 어드바이스가 적용되는 것을 확인할 수 있다.

여기서는 어차피 자바 객체로 매핑된 내용을 확인하는 것이 목표라 body 값이 읽혀 변환된 후에 적용되는 afterBodyRead 만 내용이 찍히게 로그를 남기고 읽히기 전에 적용되는 beforeBodyRead 는 단순히 실행됬다는 표시만 남게 로그를 찍었다. 로그는 귀찮아서 그냥 콘솔로 찍었다...

@ControllerAdvice(annotations = RestController.class)
public class CustomRequestBodyAdviceAdapter extends RequestBodyAdviceAdapter {

  @Override
  public Object afterBodyRead(final Object body, final HttpInputMessage inputMessage,
      final MethodParameter parameter,
      final Type targetType, final Class<? extends HttpMessageConverter<?>> converterType) {

    System.out.printf("afterBodyRead ");
    if (body instanceof ReqBody) {
      ReqBody reqBody = (ReqBody) body;
      System.out.printf("dong = %s, ho = %s\n", reqBody.getDong(), reqBody.getHo());
    }

    return body;
  }

  @Override
  public HttpInputMessage beforeBodyRead(final HttpInputMessage inputMessage,
      final MethodParameter parameter,
      final Type targetType, final Class<? extends HttpMessageConverter<?>> converterType)
      throws IOException {
    System.out.println("beforeBodyRead");
    return inputMessage;
  }

  @Override
  public Object handleEmptyBody(final Object body, final HttpInputMessage inputMessage,
      final MethodParameter parameter, final Type targetType,
      final Class<? extends HttpMessageConverter<?>> converterType) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public boolean supports(final MethodParameter methodParameter, final Type targetType,
      final Class<? extends HttpMessageConverter<?>> converterType) {
    return true;
  }

}

 

컨트롤러. 어드바이스가 적용되는 시점을 확인하기 위해 여기도 콘솔로 찍었다.

@RestController
public class ControllerBodyAdvice {

  @PostMapping(value = "/body/advice")
  public void postBodyAdvice(@RequestBody @Valid final ReqBody reqBody) {
    System.out.printf("controller dong = %s, ho = %s\n", reqBody.getDong(), reqBody.getHo());
  }

}

 

바디 객체

@Data
public class ReqBody {
  private String dong;
  private String ho;
}

 

결과

beforeBodyRead
afterBodyRead dong = 101, ho = 1001
controller dong = 101, ho = 1001

보다시피 Body 값이 읽힌 후 컨트롤러로 넘어가기 전에 값을 확인할 수 있고 어드바이스 적용 후 컨트롤러에서도 멀쩡하게 값을 확인할 수 있다!!

 

 

 

공부할 땐 시간 엄청 걸렸는데 막상 적어보니 내용이 허접하네;; API 문서나 레퍼런스 읽을 때마다 시간이 너무 걸린다. 번역기로 돌리면 아무래도 이해 안되게 바뀌는 부분이 있어서 어느정도는 돌리고 나머진 해석하려 하는데 잘될리가 없다. 영어 공부의 필요성을 느끼지만 너무 귀찮다...

Comments