Spring MVC 인터셉터 HandlerInterceptorAdapter, HandlerInterceptor 예제
스프링 인터셉터는 클라이언트 요청을 가로채서 처리하는 데 사용됩니다. 때때로 우리는 HTTP 요청을 가로채서 컨트롤러 처리기 메서드에 넘기기 전에 일부 처리를 수행하기를 원합니다. Spring MVC 인터셉터가 유용한 곳입니다.
스프링 인터셉터

스프링 인터셉터 - HandlerInterceptor
Spring HandlerInterceptor는 HTTP 요청을 가로채려는 위치에 따라 세 가지 메서드를 선언합니다.
- boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler): 이 메소드는 핸들러 메소드로 전달되기 전에 요청을 가로채는 데 사용됩니다. 이 메서드는 'true'를 반환하여 Spring이 다른 스프링 인터셉터를 통해 요청을 처리하도록 알리거나 추가 스프링 인터셉터가 없는 경우 처리기 메서드로 보내도록 해야 합니다. 이 메서드가 '거짓'을 반환하면 Spring 프레임워크는 요청이 Spring 인터셉터 자체에 의해 처리되었으며 추가 처리가 필요하지 않다고 가정합니다. 이 경우 응답 개체를 사용하여 클라이언트 요청에 대한 응답을 보내야 합니다. 개체 handler는 요청을 처리하기 위해 선택된 처리기 개체입니다. 이 메소드는 또한 Exception을 던질 수 있습니다. 이 경우 Spring MVC Exception Handling은 오류 페이지를 응답으로 보내는 데 유용해야 합니다.
- void postHandle(HttpServletRequest 요청, HttpServletResponse 응답, 개체 처리기, ModelAndView modelAndView): 이 HandlerInterceptor 인터셉터 메서드는 HandlerAdapter가 처리기를 호출했지만 DispatcherServlet이 아직 보기를 렌더링하지 않을 때 호출됩니다. 이 메서드는 보기 페이지에서 사용할 ModelAndView 개체에 추가 특성을 추가하는 데 사용할 수 있습니다. 이 스프링 인터셉터 메서드를 사용하여 핸들러 메서드가 클라이언트 요청을 처리하는 데 걸리는 시간을 결정할 수 있습니다.
- void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex): 핸들러가 실행되고 뷰가 렌더링되면 호출되는 HandlerInterceptor 콜백 메서드입니다.

스프링 인터셉터 - 컨트롤러 클래스
package com.journaldev.spring;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Handles requests for the application home page.
*/
@Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
@RequestMapping(value = "/home", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
//adding some time lag to check interceptor execution
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
logger.info("Before returning view page");
return "home";
}
}
스프링 인터셉터 메서드가 작동하는지 확인하기 위해 핸들러 메서드 실행에 약간의 처리 시간을 추가하고 있습니다.
스프링 MVC 인터셉터 - HandlerInterceptorAdapter 구현
단순화를 위해 추상 클래스 HandlerInterceptorAdapter
를 확장합니다. HandlerInterceptorAdapter는 사전 전용/사후 전용 인터셉터의 단순화된 구현을 위한 HandlerInterceptor 인터페이스의 추상 어댑터 클래스입니다.
package com.journaldev.spring;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class RequestProcessingTimeInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = LoggerFactory
.getLogger(RequestProcessingTimeInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
long startTime = System.currentTimeMillis();
logger.info("Request URL::" + request.getRequestURL().toString()
+ ":: Start Time=" + System.currentTimeMillis());
request.setAttribute("startTime", startTime);
//if returned false, we need to make sure 'response' is sent
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("Request URL::" + request.getRequestURL().toString()
+ " Sent to Handler :: Current Time=" + System.currentTimeMillis());
//we can add attributes in the modelAndView and use that in the view page
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
long startTime = (Long) request.getAttribute("startTime");
logger.info("Request URL::" + request.getRequestURL().toString()
+ ":: End Time=" + System.currentTimeMillis());
logger.info("Request URL::" + request.getRequestURL().toString()
+ ":: Time Taken=" + (System.currentTimeMillis() - startTime));
}
}
논리는 정말 간단합니다. 핸들러 메서드 실행 타이밍과 뷰 페이지 렌더링을 포함하여 요청을 처리하는 데 걸린 총 시간을 기록하고 있습니다.
Spring MVC 인터셉터 구성
스프링 인터셉터를 요청에 연결해야 합니다. mvc:interceptors 요소를 사용하여 모든 인터셉터를 연결할 수 있습니다. 매핑 요소를 통해 요청에 대한 스프링 인터셉터를 포함하기 전에 일치시킬 URI 패턴을 제공할 수도 있습니다. 최종 스프링 빈 구성 파일(spring.xml)은 다음과 같습니다.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="https://www.springframework.org/schema/mvc"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:beans="https://www.springframework.org/schema/beans"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing
infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources
in the /WEB-INF/views directory -->
<beans:bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<!-- Configuring interceptors based on URI -->
<interceptors>
<interceptor>
<mapping path="/home" />
<beans:bean class="com.journaldev.spring.RequestProcessingTimeInterceptor"></beans:bean>
</interceptor>
</interceptors>
<context:component-scan base-package="com.journaldev.spring" />
</beans:beans>
웹 애플리케이션의 다른 모든 구성 요소는 관심이 없고 특정 스프링 인터셉터 관련 구성이 없기 때문에 설명하지 않겠습니다.
Spring MVC 인터셉터 애플리케이션 테스트
서블릿 컨테이너에 애플리케이션을 배포하고 홈 컨트롤러를 호출하면 아래와 같은 로거 출력이 표시됩니다.
INFO : com.journaldev.spring.RequestProcessingTimeInterceptor - Request URL::https://localhost:9090/SpringInterceptors/home:: Start Time=1396906442086
INFO : com.journaldev.spring.HomeController - Welcome home! The client locale is en_US.
INFO : com.journaldev.spring.HomeController - Before returning view page
Request URL::https://localhost:9090/SpringInterceptors/home Sent to Handler :: Current Time=1396906443098
INFO : com.journaldev.spring.RequestProcessingTimeInterceptor - Request URL::https://localhost:9090/SpringInterceptors/home:: End Time=1396906443171
INFO : com.journaldev.spring.RequestProcessingTimeInterceptor - Request URL::https://localhost:9090/SpringInterceptors/home:: Time Taken=1085
출력은 스프링 인터셉터 메서드가 정의된 순서대로 실행됨을 확인합니다. 스프링 인터셉터를 사용하는 것이 전부입니다. 아래 링크에서 스프링 인터셉터 예제 프로젝트를 다운로드하고 여러 인터셉터를 사용하고 다른 구성 순서로 확인할 수 있습니다.
스프링 인터셉터 프로젝트 다운로드