본문으로 바로가기

인터셉터는 중간에서 가로챈다는 의미를 가진다. 스프링에서도 말 그대로 중간에 요청을 가로채서 어떠한 일을 하는 것을 말한다. 인터셉터의 정식 명칭은 핸들러 인터셉터(Handler Interceptor)이다. 클라이언트의 요청이 컨트롤러에 가기 전에 가로채고, 응답이 클라이언트에게 가기전에 가로챈다. 즉, 인터셉터는 DispatcherServlet이 컨트롤러를 요청하기 전,후에 요청과 응답을 가로채서 가공할 수 있도록 해준다.


예를 들어 로그인 기능이 있을 때, 로그인을 한 사람만 보이는 페이지가 있고, 로그인 한 사람만 글을 작성할 수 있다고 하자. 그러면 페이지 컨트롤러에서도 로그인 확인 로직이 들어가고, 글 작성 컨트롤러에서도 로그인 확인 로직이 들어가야 한다. 인터셉터를 사용하면 컨트롤러에 로직이 로그인 확인 로직이 없어도 컨트롤러에 들어가기전에 인터셉터에서 로그인 확인을 하고 컨트롤러로 보낸다. 즉, 하나의 인터셉터로 프로젝트 내의 모든 요청에 로그인 여부를 확인할 수 있다. 


인터셉터를 만들려면 HandlerInterceptorAdaptor 클래스를 상속받아야 한다. HandlerInterceptorAdaptor 클래스를 상속받으면 사용할 수 있는 3가지의 메서드들이 있다. perHandle(), postHandle(), afterHandel()이 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Intercepter extends HandlerInterceptorAdapter{
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // TODO Auto-generated method stub
        return super.preHandle(request, response, handler);
    }
 
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        // TODO Auto-generated method stub
        super.postHandle(request, response, handler, modelAndView);
    }
 
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // TODO Auto-generated method stub
        super.afterCompletion(request, response, handler, ex);
    }
 
}
cs

- 4행 : 전처리기는 클라이언트에서 컨트롤러로 요청할 때 가로채는 것이다. 쉽게 말해 컨트롤러가 호출되기 전에 실행되는 메서드이다.

- 11행 : 후처리기는 컨트롤러에서 클라이언트로 요청할 때 가로채는 것이다. 쉽게 말해 컨트롤러가 호출되고 난 후에 실행되는 메서드이다.

- 18행 : 컨트롤러의 처리가 끝나고 화면처리까지 모두 끝나면 실행되는 메서드이다.



지금 하는 설정은 하나의 요청에 대한 컨트롤러 처리의 시작과 끝을 표시해 줄 것이다. 시작해보자.


1. src/main/java에 tody.lovely.common 패키지 생성 - interceptor 패키지 생성

레벨1, 레벨2 패키지명은 알아서 해주면 된다. common패키지와 interceptor패키지를 만들어 주면 된다.


2. CommonInterceptor.java 생성


1
2
3
4
5
6
7
package tody.lovely.common.interceptor;
 
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 
public class CommonInterceptor extends HandlerInterceptorAdapter{
 
}
cs

HandlerInterceptorAdaptor 클래스를 상속했는데 @Override가 뜨지 않는다!!! 뭐야 뭐야!!


2-1. Alt+Shift+S 누르면 Override/Implements Methods... 클릭


2-2. preHandle(), postHandle() 체크 - OK


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package tody.lovely.common.interceptor;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 
public class CommonInterceptor extends HandlerInterceptorAdapter{
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // TODO Auto-generated method stub
        return super.preHandle(request, response, handler);
    }
 
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        // TODO Auto-generated method stub
        super.postHandle(request, response, handler, modelAndView);
    }
     
}
cs

그럼 이렇게 오버라이드 메소드들이 보일 것이다!



3. CommonInterceptor.java 수정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package tody.lovely.common.interceptor; 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 
public class CommonInterceptor extends HandlerInterceptorAdapter{
     
    protected Log log = LogFactory.getLog(CommonInterceptor.class);
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("===================       START       ===================");
            log.debug(" Request URI \t:  " + request.getRequestURI());
        }
        return super.preHandle(request, response, handler);
    }
 
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("===================        END        ===================\n");
        }
    }
     
}
cs

- 18행 : 전처리기에서 컨트롤러가 시작됨을 알리는 START 로그를 출력한다.

- 19행 : 현재 호출되는 URL을 알려준다.

- 28행 : 후처리기에서 컨트롤러가 끝남을 알리는 END 로그를 출력한다.



4. interceptor-servlet.xml 생성

interceptor-servlet.xml을 따로 만들지 않고 action-servlet.xml에 추가해도 상관없다. 다만 Interceptor가 DispatcherSevlet과 같은 위치에 등록되어야 된다는 것만 유의하자. action-servlet.xml에 추가하는 것도 같은 위치에 등록한 것이고, action-servlet.xml과 같은 폴더인 appServlet에 interceptor-servlet.xml을 만들어서 추가하는 것도 같은 위치에 등록한 것이다. web.xml에 가면 알 수 있을 것이다.


interceptor-sevlet.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
    <interceptors>
       <interceptor>
           <mapping path="/**"/>
           <beans:bean id="commonInterceptor" class="tody.lovely.common.interceptor.CommonInterceptor"/>
       </interceptor>
    </interceptors>
     
    <beans:bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
      
    <beans:bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
      <beans:property name="order" value="0"/>
    </beans:bean>
     
    <beans:bean id="jsonView" class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
       
</beans:beans>
cs

- 12행 : 예외 URL(exclude-mapping)을 제외한 모든 URL에 적용하고 싶을때 /** 를 쓰면 된다. 특정 URL을 쓰고싶으면 URL을 적으면 된다. 지금 우리가 사용할 것은 모든 Logger에 적용되야 하기에 /** 를 썼다.

- 20행 : ViewResolver의 순서를 정해주는 것이다. 우선 순위는 작은 값부터이다. 인터셉터가 가장 먼저 보여야 하기 때문에 0으로 설정했다.


4-1. action-servlet.xml 수정

1
2
3
4
5
6
7
    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
        <beans:property name="order" value="1"/>
    </beans:bean>
    
    <context:component-scan base-package="tody" />
cs

- 4행 : interceptor-servlet.xml에서 프로퍼티의 순서를 0으로 했기에 여기선 그 다음 1로 해준다.

- 7행 : 최상위 패키지명으로 바꿔주자. 나는 tody.lovely로 레벨1이 tody여서 tody로 했다.



5. src/main/java에 tody.lovely.common 패키지 - controller 패키지 생성


6. TestController.java 생성


TestController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package tody.lovely.common.controller;
 
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
 
@Controller
public class TestController {
     
    Logger log = Logger.getLogger(this.getClass());
     
    @RequestMapping(value="/interceptorTest")
    public ModelAndView interceptorTest() throws Exception{
         
        ModelAndView mv = new ModelAndView("");
        log.debug("인터셉터 테스트입니다!");
         
        return mv;
    }
     
}
cs

- 9행 : 컨트롤러가 실행되고 log4j가 동작하는 지 확인하려 한다.



7. pom.xml에 jsonView 추가

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- MappingJacksonJsonView -->
<dependency>
    <groupid>org.codehaus.jackson</groupid>
        <artifactid>jackson-mapper-asl</artifactid>
    <version>1.9.13</version>
</dependency>
 
<dependency>
    <groupid>org.codehaus.jackson</groupid>
        <artifactid>jackson-core-asl</artifactid>
    <version>1.9.13</version>
</dependency>
<!--  -->
cs

interceptor-servlet.xml에 jsonView를 bean등록했다.



8. 서버실행 - 주소창에 /interceptorTest 입력

404 에러가 뜨는 게 정상이다. 왜냐면 view 부분에 jsp를 주지 않았기 때문!


콘솔창을 보자. 

START와 END 그리고 인터셉터 테스트입니다! 가 뜨면 인터셉터 설정이 끝난 것이다. 어떤 URL이 요청되었고 요청한 URL의 컨트롤러 정보, 그리고 컨트롤러의 시작과 끝을 콘솔창에서 쉽게 확인할 수 있게 되었다. 안해도 될 거 같지만, 한번 해 놓으면 정말 편하다.


******* 혹시 여기서 아래와 같은 에러가 뜬다면 http://to-dy.tistory.com/22?category=700248 여기 참고!!

org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: URL [jar:file:/C:/Program%20Files/Java/jre1.8.0_161/lib/ext/jfxrt.jar!/com/sun/glass/ui/Accessible.class]; nested exception is java.lang.ArrayIndexOutOfBoundsException: 3805021



에고 에러때문에 고생 좀 했다ㅠㅠ