Dev/Spring Boot

스프링의 다양한 기능(Filter, Interceptor)

OK-가자 2022. 3. 2. 17:41

Filter-Interceptor 활용하기.

🔔😁🎅🤔

🤔🤔🤔Filter가 뭘까?

Filter란 Web Application에서 관리되는 영역으로써 spring Boot 에서 Client로 부터 오는 요청/응답에 대해서 최초/최종 단계의 위치에 존재하며, 이를 통해서 요청/응답의 정보를 변경하거나,Spring에 의해서 데이터가 변환되기 전의 순수한 Client의 요청/응답 값을 확인 할 수 있다.

유일하게 ServletRequest,ServletResponse 의 객체를 변환 할 수 있다.

주로 request/response 의 Logging 용도로 활용하거나, 인증과 관련된 Logic들을 헤당 Fliter에서 처리 한다.

이를 선/후 처리 함으로써 Service business logic과 분리 시킨다.
AOP는 객체로 Mapping 되었기때문에 spring에 들어왔기 때문에 순수하지 않다는 차이점이 있다.
Filter -->> DispatcherServlet-->>HandlerInterceptor-->>AOP동작
그림으로 보면

백문이 불여일타

Request와 Response내용을 Log로 남기는 Filter 만들어 보자.

User.class 만들고 Apicontroller셋팅하고

@Slf4j
@Component //Spring Bean으로 관리되어야함
public class GlobalFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //전처리
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;

        String url = httpServletRequest.getRequestURI();

        BufferedReader br = httpServletRequest.getReader();
        br.lines().forEach(line -> {
            log.info("url : {}, line: {}",url , line);
        });

    }
}

이렇게 필터를 걸고 slf4j를 사용하여 로그를 찍으면

이렇게 잘 찍힌다.

🔔 하지만!!

Filter에서 BufferedReader 를 사용하면
BufferedReader특성상 내용을 한번 읽으면 그내용을 뒤에서 못읽는다 즉 사라진다!!!

🤔 앵??? 그럼 어떻하죠? ServletRequest로 LOG 못찍나요? 아뇨 아래와 같이 하면 된다.

ContentCachingRequestWrapper를 사용하면 된다.

ContentCachingRequestWrapper안에있는 ByteArrayOutputStream에 내용을 미리 담아두는데 뒤에서 누가 읽을때 여기 담겨진 내용들을 뒤에서 읽을수 있게 해준다.

public class GlobalFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //전처리
        ContentCachingRequestWrapper httpServletRequest = new ContentCachingRequestWrapper((HttpServletRequest) request);
        ContentCachingResponseWrapper httpServletResponse = new ContentCachingResponseWrapper((HttpServletResponse) response);
        //이렇게 한다고 해도 Byte의 길이만 설정해 두고 컨탠츠들은 복사하지 않는다 그래서 doFilter 다음에 실행시킨다.

        chain.doFilter(httpServletRequest, httpServletResponse);
        //후처리

        String url = httpServletRequest.getRequestURI();
        String reqContent = new String(httpServletRequest.getContentAsByteArray());
        log.info("request url : {}, request body : {}", url, reqContent);

        String resContent = new String(httpServletResponse.getContentAsByteArray());
        int httpStatus = httpServletResponse.getStatus();
        //Response도 마찬가지로 한번 읽으면 사라진다. 그래서 다시 채워줘야한다.ㅉ
        httpServletResponse.copyBodyToResponse(); //다시한번 더 바디를 채워준다.

        log.info("response status : {}, responseBody : {}", httpStatus, resContent);

    }
}

와우! 이렇게 하면 로깅이 잘 찍힌다.

마지막으로 Filter 범위를 설정해주자.

@Slf4j
@WebFilter(urlPatterns = "/api/user/*")
@Component //Spring Bean으로 관리되어야함
public class GlobalFilter implements Filter {

이렇게 해서Filter로 로그남기기 끝

이거 좋아 완전 좋아~~!!