웹사이트 검색

Spring MVC 인터셉터 HandlerInterceptorAdapter, HandlerInterceptor 예제


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

스프링 인터셉터

스프링 인터셉터 - HandlerInterceptor

Spring HandlerInterceptor는 HTTP 요청을 가로채려는 위치에 따라 세 가지 메서드를 선언합니다.

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

출력은 스프링 인터셉터 메서드가 정의된 순서대로 실행됨을 확인합니다. 스프링 인터셉터를 사용하는 것이 전부입니다. 아래 링크에서 스프링 인터셉터 예제 프로젝트를 다운로드하고 여러 인터셉터를 사용하고 다른 구성 순서로 확인할 수 있습니다.

스프링 인터셉터 프로젝트 다운로드