2020-7-6 스프링 MVC(3) 인터셉터
인터셉터
핸들러인터셉터 => 핸들러인터셉터와 AOP의 차이는??
-
핸들러 맵핑에 설정할 수 있는 인터셉터.
-
핸들러를 실행하기 전, 후(렌더링 전), 완료(렌더링이 끝난이후)시점에 부가작업을 하고 싶은 경우에 사용할 수 있다.
- preHandler => 요청처리 => postHandler => 뷰 랜더링 => afterCompletation
-
여러 핸들러에서 반복적으로 사용한느 코드를 줄이고 싶을때 쓸 수 있다.(로깅, 인증 체크, Locale…)
-
boolean preHandle(request, response, handler)
- 핸들러 실행하기 전에 호출
- 핸들러에 대한 정보가 제공되기때문에 서블릿 필터에 비해 로직을 더 잘 구현할 수 있다.
- 리턴값으로 계속 다음 인터셉터 또는 핸들러로 요청, 응답을 전달할지(true), 이곳에서 처리가 끝났는지(false) 알린다.
-
void postHandle(request, response, modelAndView)
- 핸들러 실행이 끝나고 아직 뷰를 렌더링하기 이전에 호출
- 뷰에 전달할 추가적이거나 여러 핸들러에 공통적인 모델 정보를 담는데 사용
- 인터셉터 역순으로 호출 => 인터셉터가 여러개일때.
- preHandler1 => preHandler2 => 요청처리 => postHandle2 => postHandle1 => 뷰 => afterCompletion2 => afterCompletion1
- 비동기적인 요청 처리 시에는 호출되지 않는다.
-
void afterCompletion(request, response, handler, ex)
- 요청 처리가 완전 끝난 뒤(뷰 렌더링 끝난뒤)에 호출됨
- preHandler에서 true를 리턴한 경우에만 호출된다.
- 인터셉터 역순으로 호출
- 비동기적인 요청에는 호출 안된다.
-
서블릿필터와 어떤 차이가 있는가?
- 서블릿보다 구체적인 처리가 가능하다.
- 서블릿은 보다 일반적인 용도의 기능을 구현하는데 사용
- XSS를 방지하기 위해서는 서블릿필터를 써라. 인터셉터랑은 전혀관계없다.
-
인터셉터를 구현하기 위해서는 HandlerInterceptor를 구현해라. 사용하기 위해서는 WebConfigurer를 구현한 클래스에서 addInterceptor()를 구현해라
-
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new GreetingInterceptor()); // .order(value)를 통해 순서를 정할 수 있다. order는 음수일수록 순위가 높다. registry.addInterceptor(new AnotherInterceptor()); } } public class AnotherInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle2"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle 2"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion2"); } } public class GreetingInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle1"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle 1"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion1"); } } //result preHandle1 preHandle2 postHandle 2 postHandle 1 afterCompletion2 afterCompletion1 // order적용 registry.addInterceptor(new GreetingInterceptor()).order(-1); registry.addInterceptor(new AnotherInterceptor()).order(-2); preHandle2 preHandle1 postHandle 1 postHandle 2 afterCompletion1 afterCompletion2 // 패턴적용 registry.addInterceptor(new AnotherInterceptor()) .addPathPatterns("/hi") .order(-2); preHandle1 postHandle 1 afterCompletion1
- addPathPattern을 통해 특정패턴에만 적용시킬 수 있다.
-
리소스핸들러
-
이미지, JS, CSS, HTML을 처리하는 핸들러 등록하는 방법
-
디폴트 서플릿
- 서블릿 컨테이너가 기본으로 제공하는 서블릿으로 정적인 리소스를 처리할 때 사용
-
스프링MVC 리소스 핸들러 매핑등록
- 가장낮은 우선순위로 등록.
- 다른 핸들러매핑이 “/”이하의 요청을 처리하도록 허용하고 최종적으로 리소스핸들러가 처리
-
설정
- 어떤 요청 패턴을 지원할것인가
- 어디서 리소스를 찾을까
- 캐싱
- ResourceResolver: 요청에 해당하는 리소스를 찾는 전략 => 캐싱, 인코딩(gzip, brotli), Webber
- ResourceTransformer : 응답으로 보낼 리소스를 수정하는 전략 => 캐싱, CSS링크, HTML5
-
스프링부트 : 기본 정적 리소스 핸들러와 캐싱제공(resources디렉토리의 하위에 있는 static, public이라는 디렉토리를 지원)
-
@Test public void helloStatic() throws Exception { this.mockMvc.perform(get("/index.html")) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().string(Matchers.containsString("hello index"))); }
-
-
스프링부트가 기본으로 제공하는것이 아닌 임의로 리소스 핸들러를 등록하고 싶으면 WebConfigurer를 구현한 인터페이스에서 addResourceHandlers를 구현해라
-
@Configuration public class WebConfig implements WebMvcConfigurer { .... @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/mobile/**") .addResourceLocations("classpath:/mobile/") .setCacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES)); } } @Test public void helloStatic() throws Exception { this.mockMvc.perform(get("/mobile/index.html")) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().string(Matchers.containsString("hello mobile"))) .andExpect(header().exists(HttpHeaders.CACHE_CONTROL)); }
-
캐시에 관련된 헤더가 응답헤더에 함께 추가된다. 리소스가 변경이 안되면 10분동안 유지. 10분 이내로 동일한 요청을 보내게 되면 304응답과 함께 캐시된 결과를 준다. 10분 안에 리소스가 변경되면 변경된 리소스를 리턴
- addReourcehandlers에 있는 addResourceChain(boolean cacheResource) 운영중에는 캐시를 사용(true) 개발중에는 false를 주로 쓴다.
-