본문 바로가기
Project/jp

(7)인터셉터(Interceptor) 설정하기

by 김뚱 2018. 7. 19.

1. MVC 패턴

Interceptor를 이해하기전 MVC패턴&DipatcherServlet 역할에 대하여 이해하는 것이 중요하다.
MVC 패턴은 Model-View-Controller 으로 이루어져 있으며 인터페이스와 비즈니스 로직을 분리하여 웹 개발을 하는 것이다.


1-1) Model : 애플리케이션의 정보, 즉 데이터를 의미한다. 

1-2) View : 사용자에게 보여주는 화면(jsp)을 의미한다.

1-3) Controller : model과 view의 데이터 교환역할을 한다.


MVC 패턴에서는 Servlet이 흐름을 제어하는 Controller 역할을 수행한다. 모든 클라이언트의 요청은 서블릿에 전달되어 서블릿이 클라이언트의 요청에 따라 비즈니스 로직을 호출하고 그 결과에 따라 View에 해당하는 JSP를 호출하는 방식이다.



2. DispatcherServlet

MVC에서 DispatcherServle은 각각 분리하여 만든 Model파트 Controller파트 View파트를 조합하여 브라우저로 출력해주는 역할을 수행하는 클래스이다.
DispatcherServlet은 사용자(client)의 요청을 받아서 해당 요청에 매핑되는 컨트롤러와 연결한 후, 컨트롤러에서 정의된 view를 사용자의 브라우저에
출력하는 역할을 수행한다.

처리로직은 다음과 같다.


1) 클라이언트 : url로 접근하여 정보를 요청

2) Dispatcher Servlet : 해당 요청을 매핑한 컨트롤러가 있는지 검색

>>>요청을 가로챌수 있는 이유 : web.xml에서 Dispatcher의 <url-pattern>을 '/'로 등록했기 때문이다.

3) Handler Mapping : Controller에 처리요청

4) Controller : client의 요청을 처리하고 결과를 출력할 view 이름을 리턴

5) DispatcherServlet : Controller에서 보내온 view이름을 토대로 처리 view 검색

6) ViewResolver : 처리결과를 View에 송신

7) View : 처리결과가 포함된 View DispatcherServlet에 송신

8) DispatcherServlet : client에 최종결과를 출력



3. Interceptor 설정

Intercept = '가로막다' 라는 뜻이 있다. 
Interceptor의 정확한 명칭은 핸들러 인터셉터(Handler Interceptor)이다.
Interceptor는 DispatcherServlet이 Controller를 호출하기 전, 후에 요청과 응답을 가로채서 수행할 수 있도록 한다.  
즉, Interceptor는 DispatcherServlet과 같은 위치에 등록이 되어있어야 한다.
>>> action-servlet에 interceptor를 설정함으로서 같은 위치에 등록한 것을 의미한다.

예를 들면 로그인 여부를 판단하여 로그인시에는 요청 페이지로 이동 그렇지 않다면 메인화면으로 이동시킨다고 가정해보자. 

클라이언트에서 요청이 왔을 때 인터셉터에서 로그인 여부를 판단하여 요청페이지로 이동하거나 메인페이지로 이동시킬 수 있다.

즉, 프로젝트내의 모든 요청에서 한개의 인터셉터로 관리할 수 있다.



3-1) LoggerInterceptor.java 

HandlerInterceptorAdapter 클래스를 상속받아서 만든다. 

LoggerInterceptor에서는 전처리기와 후처리기를 구현하였다.

1) client > controller : 전처리기

2) controller > client : 후처리기

이를 action-servlet.xml에서 <mvc:mapping path>를 통해서 Interceptor가 동작할 URL을 지정할 수 있다.

logger가 모든 요청에서 동작을 하도록 설정하기 위해 전체 패스를 의미하는 "/**"로 설정하였다. 


<mvc:interceptors>

<mvc:interceptor>

<mvc:mapping path="/**" />

<bean id="loggerInterceptor"

class="jp.com.logger.LoggerInterceptor" />

</mvc:interceptor>

</mvc:interceptors>


여기서 문제점은 DispatcherServlet이 모든 요청을 컨트롤러의 넘겨주는 방식에서 이미지나 HTML 파일, 스크립트, 스타일시트 등을 불러오는 요청마저 전부 컨트롤러로 넘겨버려 제대로 자원을 불러올 수 없는 상황이 발생한다는 것이다.

DispatcherServlet이 해당 요청을 처리할 컨트롤러를 찾지 못했다는 에러메시지가 로그에 기록될 것이다. 


>해결방법

영역분리를 하여 리소스 관리&확장을 하는 것이다. 

이때 <mvc:resources></mvc:resources >태그를 사용한다.

처리동작으로는 먼저 DispatcherServlet을 통해 들어온 요청을 처리하는데 해당 요청에 대한 컨트롤러를 찾을 수 없다면 아래와 같이 설정된 경로를 검색하여 해당 자원을 찾아내게 되는 것이다. 


<mvc:resources mapping="/js/**" location="/js/" />

<mvc:resources mapping="/css/**" location="/css/" />

<mvc:resources mapping="/images/**" location="/images/" />

<mvc:resources mapping="/resources/**" location="/resources/" />


3-2) LoggerAspect.java 

어느 영역에서 log를 출력할지 설정하는 클래스 이다. 




>>>JP 프로젝트의 LoggerInterceptor.java


package jp.com.logger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class LoggerInterceptor extends HandlerInterceptorAdapter {

    private static final Logger log = Logger.getLogger(LoggerInterceptor.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 model) throws Exception {
        if (log.isDebugEnabled()) {
            log.debug(
                    "====================================== END ======================================\n");
        }
    }

}




>>>JP 프로젝트의 LoggerAspect.java


package jp.com.logger;

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class LoggerAspect {

    protected Logger log = Logger.getLogger(this.getClass());

    static String name = "";
    static String type = "";

    @Around("execution(* jp..controller.*Controller.*(..)) or execution(* jp..service.*Impl.*(..)) or execution(* jp..dao.*DAO.*(..))")
    public Object logPrint(ProceedingJoinPoint joinPoint) throws Throwable {
        /**
         * joinPoint가 method이면 해당 class명을 가져온다
         */
        type = joinPoint.getSignature().getDeclaringTypeName();
        if (type.indexOf("Controller") > -1) {
            name = "Controller \t : ";
        } else if (type.indexOf("Service") > -1) {
            name = "Service \t\t : ";
        } else if (type.indexOf("DAO") > -1) {
            name = "DAO \t\t : ";
        }
        log.debug(name + type + "." + joinPoint.getSignature().getName() + "()");
        
        return joinPoint.proceed();
    }

}




>>>JP 프로젝트의 web.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="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
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- DispatcherServlet Context: defines this servlet's request-processing
        infrastructure -->

    <!-- Enables the Spring MVC @Controller programming model -->
    <mvc:annotation-driven />

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving
        up static resources in the ${webappRoot}/resources directory -->
    <mvc:resources mapping="/js/**" location="/js/" />
    <mvc:resources mapping="/css/**" location="/css/" />
    <mvc:resources mapping="/images/**" location="/images/" />
    <mvc:resources mapping="/resources/**" location="/resources/" />

    <mvc:annotation-driven>
        <mvc:argument-resolvers>
            <bean class="jp.com.resolver.ParamCollectorArgumentResolver" />
        </mvc:argument-resolvers>
    </mvc:annotation-driven>
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**" />
            <bean id="loggerInterceptor"
                class="jp.com.logger.LoggerInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>
    
    <aop:aspectj-autoproxy />
    <bean id="loggerAspect" class="jp.com.logger.LoggerAspect" />
    
    <!-- Resolves views selected for rendering by @Controllers to .jsp resources
        in the /WEB-INF/views directory -->
    <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"
        p:order="0" />
    <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"
        p:order="1" p:viewClass="org.springframework.web.servlet.view.JstlView"
        p:prefix="/WEB-INF/views/" p:suffix=".jsp" />

    <bean id="jsonView"
        class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
    <util:list id="messageConverters">
        <bean
            class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"
            p:supportedMediaTypes="application/json" />
    </util:list>
    
    <!-- CORS setting : https://spring.io/blog/2015/06/08/cors-support-in-spring-framework#xml-namespace -->
<import resource="classpath*:spring/cors-config.xml" />

    <context:component-scan base-package="jp" />
</beans>


728x90
반응형

'Project > jp' 카테고리의 다른 글

(9)HandlerMethodArgumentResolver 적용  (1) 2018.07.21
(8)데이터베이스(Oracle) 연결  (0) 2018.07.20
(6)로그(log4j) 설정하기  (0) 2018.07.19
(5)web.xml 설정하기  (0) 2018.07.19
(4)pom.xml 설정하기  (0) 2018.07.14

댓글