스프링은 이미 AOP를 제공하고 있지만, AOP는 너무 범용적인 방법이다.
스프링 MVC는 여러 컨트롤러에 공통으로 적용되는 기능을 구현하는 방법인 HandlerInterceptor를 제공하고 있으며, 공통 기능을 다수의 URL에 적용할 수 있게 된다.
org.springframework.web.servlet.HandlerInterceptor 인터페이스를 사용하면, 다음의 세가지 시점에 대해 공통 기능을 넣을 수 있다.
세 시점을 처리하기 위해 HandlerInterceptor 인터페이스는 다음과 같이 세 개의 메서드를 정의하고 있다.
package org.springframework.web.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.method.HandlerMethod;
public interface HandlerInterceptor {
boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object Handler) throws Exception;
void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception;
void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) throws Exception;
preHandle() 메서드는 컨트롤러/핸들러 객체를 실행하기 전에 필요한 기능을 구현할 때 사용된다. handler 파라미터는 웹 요청을 처리할 컨트롤러/핸들러 객체이다.
이 메서드를 사용하면 접근 권한이 없는 경우 컨트롤러를 실행하지 않는다거나, 컨트롤러를 실행하기 전에 컨트롤러에서 필요로 하는 정보를 생성하는 등의 작업이 가능하다.
postHandle() 메서드는 컨트롤러/핸들러 객체가 정상적으로 실행된 이후에 추가 기능을 구현할 때 사용된다. 만약 컨트롤러가 예외를 발생하면 postHandle() 메서드는 실행되지 않는다.
afterCompletion() 메서드는 클라이언트에 뷰를 전송한 뒤에 실행된다.
만약 컨트롤러를 실행하는 과정에서 예외가 발생하면,
이 메서드의 네 번째 파라미터(Exception ex)로 전달된다.
예외가 발생하지 않았다면 네 번째 파라미터는 null이 된다.
따라서, 컨트롤러 실행 이후 발생한 예외를 로그로 남긴다거나, 실행 시간을 기록하는 등의 후처리를 하기에 적합한 메서드이다.
HandlerInterceptorAdapter 클래스는 HandlerInterceptor 인터페이스를 구현하고 있는데 각 메서드는 아무 기능도 수행하지 않는다.
따라서, HandlerInterceptor 인터페이스의 메서드를 모두 구현할 필요가 없다면, HandlerInterceptorAdapter 클래스를 상속받은 뒤 필요한 메서드만 재정의하면 된다.
HandlerInterceptor를 구현했다면, 웹 요청을 처리할 때 HandlerInterceptor가 적용되도록 설정에 추가하는 것이다. 추가하는 방법은 다음과 같다.
<mvc:interceptors>
<bean id="exerciseInterceptor"
class="com.spring.exercise.ExerciseInterceptor" />
</mvc:interceptors>
<mvc:interceptors> 태그는 HandlerInterceptor 설정과 경로 설정을 함께 설정할 때 사용된다.
위 설정의 경우 <mvc:interceptors> 태그 내부에 빈 객체를 HandlerInterceptor로 사용하고, DispatcherServlet이 처리하는 모든 요청에 대해 HandlerInterceptor를 적용하게 된다.
만약, 특정 요청 경로에 대해서만 HandlerInterceptor를 적용하고 싶다면 아래과 같이 중첩된 <mvc:interceptor> 태그를 사용한다.
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/event/**" />
<mvc:mapping path="/folders/**" />
<bean class="com.spring.exercise.ExerciseInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
위 설정에서 <mvc:mapping>은 HandlerInterceptor를 적용할 요청 경로 패턴을 지정한다. (이 경로는 컨텍스트 경로를 제외한 나머지 경로와 매핑된다.)
<mvc:mapping> 태그로 지정한 경로 패턴에 적용될 HandlerInterceptor 는 < bean>태그를 이용해서 지정한다.
(출처: 웹 개발자를 위한 Spring 4.0 프로그래밍, 저자 : 최범균)