requestbody 의 json Filter
Post방식으로 application/json 타입의 데이터를 Servlet Filter 나 Spring Interceptor 에서 처리하기 위해서 HttpServletRequest의 InputStream을 읽어들여야 한다.
그러나 HttpServletRequest의 InputStream은 한 번 읽으면 다시 읽을 수 없다
우선 wrapper 객체를 하나 만들어서 일단 InputStream을 읽어서 작업후 >>이미 읽었던 데이터로 다시 InputStream을 생성해 돌려주도록 만드는 방법이 존재한다.
결국 inputstream 으로 한번 읽어들이면 다시 못 읽어서 다시 inputstream으로 생성해 돌려줘야함
filter , Interceptor 차이?
공통점 : Interceptor 과 filter 는 Servlet 단위에서 실행됨
Vs(번외) AOP는 메소드 앞에 proxy 패턴의 형태에서 실행됨
Filter
- 그림과 같이 filter 가 가장 밖에 있음
- Dispatcher Servlet 의 앞 단을 처리함
Interceptor
- DispatcherServlet에서 Handler(Controller)로 가기전에 정보 처리임
- preHandle같은 경우 controller 들어가기 전에 실행 되기 때문에 false 가 되면 controller로 보내지지 않음 (동작이 안됨)
순서
Request -> Servlet Filter -> Dispatcher Servlet -> HandlerInterceptor -> Controller
filter 예시
@WebFilter(urlPatterns= "/api/*")추가 후 (web.xml 에 넣는것 대신)
package com.example.springstudy.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(urlPatterns= "/api/*")
public class TestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//filter 생성 시 처리
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//다음 Filter 실행 전 처리 (preHandle)
//다음 filter-chain에 대한 실행 (filter-chain의 마지막에는 Dispatcher servlet실행)
filterChain.doFilter(servletRequest, servletResponse);
//다음 Filter 실행 후 처리 (postHandle)
}
@Override
public void destroy() {
//filter 제거 시 처리 (보통 자원의 해제처리를 한다.)
}
}
Interceptor 예시
public class MyInterceptor implements HandlerInterceptor{
// controller로 보내기 전에 처리하는 인터셉터
// 반환이 false라면 controller로 요청을 안함
// 매개변수 Object는 핸들러 정보를 의미한다. ( RequestMapping , DefaultServletHandler )
@Override
public boolean preHandle(
HttpServletRequest request, HttpServletResponse response,
Object obj) throws Exception {
System.out.println("MyInterCeptor - preHandle");
return false;
}
// controller의 handler가 끝나면 처리됨
@Override
public void postHandle(
HttpServletRequest request, HttpServletResponse response,
Object obj, ModelAndView mav)
throws Exception {
}
// view까지 처리가 끝난 후에 처리됨
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response,
Object obj, Exception e)
throws Exception {
}
}
WebAppConfiguration.java 에 추가
@Autowired
@Qualifier(value = "httpInterceptor")
private HandlerInterceptor interceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor) .addPathPatterns("/**");
}
실행 방법
데이터를 주고 받는 형태가 JSON 형태이다.(Requestbody) Parameter로 주고 받는 형태가 아니었기 때문에 인터넷에 나와있는 일반적인 필터링 방법과 네이버에서 제공하는 루시도 사용하기 애매한 방법이였다.
그러던 도중>> requestbody로 받는 데이터는 HttpServletRequest의 InputStream을 읽어들여 처리할 수 있다는 글을 보고 데이터를 처리 해줬는데 Message가 없다는 오류가 떴다.
이유를 알아보니 한번 inputstream에서 빠져나와 작업을 하게되면 다시 쓸 수 없다는것 ! 그래서 다시 inputstream에 넣어줘야 한다.
그래서 reqeustWrapper.java에 서블렛스트림을 오버라이드 시켜 작업을 해줬다.
이후 필터링을 하는게 아니라 아예 필터해야할 값에 걸리게 되면 api를 보내지 못하게 처리하려고 만들었다.
처음에는 Interceptor을 써서 preHandle에 requestWrapper객체로 함수를 불러와 값을 구분해주고 필터에 걸리면 false로 리턴해주는 방식으로 만들었지만(Controller로 가지 못하게 막는 방식), 너무 불편하고 굳이 Interceptor까지 사용해야하나 라는 생각이 들어 doFIilter 가 있는 부분에 체크를 해줘서 filter 할 값이라면 doFilter이 돌아가지 못하게 하는 방식으로 했더니 성공하였다
'개발(라이브러리,프레임워크) > Spring boot' 카테고리의 다른 글
Bean 생성 관리 (0) | 2021.03.29 |
---|---|
intellij 초기 설정 , vue.js와 연동 (0) | 2021.03.28 |
Spring MVC , Spring Boot (0) | 2019.11.19 |
REST API (0) | 2019.11.18 |
Spring Boot VS Spring (0) | 2019.06.28 |