728x90

우선 다양한 방법으로 request body 한번만 읽어올수 있는 문제를 해결 할 수 있지만 내가 해결 한방 법중에 가장 심플한 방법을 소개한다.

  • 필터를 만든다.
  • 끝!!!

    너무 간단해서 할말을 잃었다.

  • 그럼 코드를 보면서 한번 이해해 보자

커스텀 필터를 아래와 같이 만든다!!!

  • Order는 1번으로 최상단!!

    /**
    * JSON Body를 여러번 읽을 수 있게 커스텀 필터를 추가
    */
    @Component
    @Order(1)
    public class RequestBodyFilter extends OncePerRequestFilter {
    
      @Override
      protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
          chain.doFilter(new MultiReadHttpServletRequest(request), response);
      }
    
      private class MultiReadHttpServletRequest extends HttpServletRequestWrapper {
          private ByteArrayOutputStream cachedBytes;
    
          public MultiReadHttpServletRequest(HttpServletRequest request) {
              super(request);
          }
    
          @Override
          public ServletInputStream getInputStream() throws IOException {
              if (cachedBytes == null) {
                  cacheInputStream();
              }
    
              return new CachedServletInputStream(cachedBytes.toByteArray());
          }
    
          @Override
          public BufferedReader getReader() throws IOException {
              return new BufferedReader(new InputStreamReader(getInputStream()));
          }
    
          private void cacheInputStream() throws IOException {
              /* Cache the inputstream in order to read it multiple times. For
               * convenience, I use apache.commons IOUtils
               */
              cachedBytes = new ByteArrayOutputStream();
              IOUtils.copy(super.getInputStream(), cachedBytes);
          }
    
    
    /* An input stream which reads the cached request body */
    private static class CachedServletInputStream extends ServletInputStream {

        private final ByteArrayInputStream buffer;

        public CachedServletInputStream(byte[] contents) {
            this.buffer = new ByteArrayInputStream(contents);
        }

        @Override
        public int read() {
            return buffer.read();
        }

        @Override
        public boolean isFinished() {
            return buffer.available() == 0;
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setReadListener(ReadListener listener) {
            throw new RuntimeException("Not implemented");
        }
    }
}

}



## 이후 나는 이 값을 interceptor에서 처리하기 위해서 Requestbody값을 읽을 필요가 있었다.
- 그래서 인터셉터를 아래와 같이 만들어서 사용중이다
- 인증 관련 처리를 하고 있다.

```java
@Slf4j
public class AuthorizationInterceptor implements HandlerInterceptor {

    public static final String X_PARTNER_NAME = "X-Partner-Name";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        final String requestJsonBody = getRequestJsonBody(request);
        log.info("requestJsonBody : " + requestJsonBody);

        log.info("start check");
        checkIfClientValid(request);
        log.info("end check");

        // BniTokenService.instance.get()
        return HandlerInterceptor.super.preHandle(request, response, handler);

    }

    /**
     * 유효한 Client인지 체크
     *
     * @param request
     */
    private void checkIfClientValid(HttpServletRequest request) {
        Client.findByClient(request.getHeader(X_PARTNER_NAME));
    }


    /**
     * JSON Body를 읽어온다
     *
     * @param request
     * @return
     */
    private String getRequestJsonBody(HttpServletRequest request) {
        try {
            // JSON 인 경우만 Body를 읽도록 필터링
            if ("application/json".equalsIgnoreCase(request.getHeader("Content-Type"))) {
                return IOUtils.readLines(request.getInputStream()).stream().map(f -> f.trim()).collect(Collectors.joining());
            }
        } catch (Exception e) {
            log.warn(e.getMessage(), e);
        }

        return null;
    }

}

여기서 유효한 Client가 아니면 throw를 던진다.

  • 끝!!! 쉽지 않은가?
복사했습니다!