SpringFramework/BASIC

[Interceptor] 세션검증 공통코드 처리 정리 및 예시

유혁스쿨 2020. 9. 10. 02:08
728x90
반응형

Interceptor

 

Interceptor는 Controller를매핑하기 전에 DispatcherServlet과 Controller 사이에 두는것이 Interceptor라는 장벽입니다.

 

우리가 BoardController라고 했을 때, BoardController의 어떠한 요청에 진입할때 Interceptor로 제한을 걸수 있게됩니다.

즉, Interceptor의 역할을 기능제한을 수행하는것 입니다.

 

Interceptor의뜻인 중간에 탈취한다 는 뜻과 연관이있습니다.

 

DispatcherServlet이 글쓰기요청을 받는다면 BoardController에서 일일히 글쓰기에대한 메서드, 글수정에대한 메서드, 글삭제에대한 메서드에서 세션검증에대한 코드를 각각 넣어줘야 할 텐데 공통적인 코드이므로 Interceptor를 사용하여 한번에 처리할수 있다는것입니다.

 

Interceptor설정에서 글쓰기 글수정 글삭제에대한 interceptor를 발동시키라고 미리 설정을 해놓았다면,

DispatcherServlet에 게시판에대한 어떤요청이 들어오면 컨트롤러에 알리기 전에 글쓰기 요청이 들어오면

Interceptor에서 중간에 가로채어 Session에대한 검증 즉, 로그인이되었는지, 회원인지에대한 검증을 미리해버린다는것입니다.

 

이렇게 중간에 가로채어 미리 검증하여 컨트롤러에 전달하기 전에 차단/통과의 결정을 미리 하게되는것 입니다. 

Interceptor설정에서 막을 uri를 작성해두고 공통적으로 session검사를 하도록 Interceptor처리를 한다는것 입니다.

 

요청이 들어오면 제일먼저 공통적인 처리를 DispatcherServlet을 통해 거쳐가고 Controller로 진입하기 전 중간에 Interceptor를 두어 preHandle() , postHandle() , afterCompletion() 의 기능을 가지고 있습니다.

preHandle() -> 컨트롤러로 진입하기 전에 검사, prehandle에 session검증작업을 걸어놓는다면 컨트롤러에게 가기전에 uri를 확인후 session유무를 판단하여 컨트롤러로의 차단및통과를 수행합니다.

 

postHandle() -> 일단은 컨트롤러로 진입시켜준 후 다시 view에게 돌아갈때 공통적으로 들고가야할 Model이 있다거나 할때 postHandle을 사용합니다.

 

afterCompletion() -> 뷰와 소통하기 직전에 작동합니다.

 

DispatcherServlet으로부터 Controller로 넘어갈때 Interceptor가 작동하게되고, false를 리턴한다면 다음 내용을 수행하지않게됩니다 , 즉 컨트롤러로 넘어가지 않게 되는것 입니다.

만약 true를 리턴한다면 통과되어 Controller로 넘어가게됩니다.

 

Spring에서 Interceptor를 사용하기 위해서는 인터셉터 클래스를 제작한 후에 HandlerInterceptorAdaptor라는 클래스를 상속받아 인터셉터 클래스로 지정을 하고 빈등록을 한다면 Interceptor처리를 자동으로 할수있게 됩니다.

 

 

실습 예제를 통해 Interceptor 설정과 동작과정을 각각 정리하겠습니다.

 

컨트롤러 로직입니다.

@Controller
public class InterceptorController {

    @GetMapping("/test1")
    public String test1() {
        return "test/inter-test";
    }
	
    @GetMapping("/test2")
    public String test2(Model model) {
        model.addAttribute("data","Hello world");
        return "test/inter-test";
    }	
}

 

inter-test.jsp 파일입니다.

<body>

<h2>인터셉터 테스트</h2>
<a href="/test2">test2로 이동</a>
<p>
	# 데이터 : ${data}
</p>


</body>

 

HandlerInterceptorAdaptor클래스를 상속받은 인터셉터기능을 해줄 클래스 로직입니다.

public class TestInterceptor extends HandlerInterceptorAdapter{
	
		
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
        System.out.println("테스트 인터셉터의 preHandle이 작동!!");
        return true;
    }
	
	
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
        ModelAndView modelAndView) throws Exception {
        System.out.println("테스트 인터셉터의 postHandle 작동!!");
        Object data = modelAndView.getModel().get("data"); 
        if(data != null) {
            request.getSession().setAttribute("data", data);
            response.sendRedirect("/test1");
        }
    }
}

이곳에는 공통적인 기능을 수행할 인터셉터 내용을 등록해줍니다.

인터셉터 클래스는 공통적인 기능에 따라서 여러개 만들수 있습니다.

 

 

인터셉터를 설정합니다.

    <beans:bean id="testInterceptor" class="com.spring.mvc.board.commons.interceptor.TestInterceptor" />
    <interceptors>
        <interceptor>
            <mapping path="/test1"/>
            <mapping path="/test2"/>
            <beans:ref bean="testInterceptor" />
        </interceptor>
    </interceptors>

인터셉터의 빈등록 및 설정에 대한 설명만 간략하게 하겠습니다.

우선 빈등록은 사용하기 위해서 컨테이너에 객체를 미리 등록해둔것이며, 컨트롤러마다 각각의 공통기능이 다르기때문에 빈을 각각 등록해줘야합니다. 현재 하나의 test컨트롤러에서 하나의 인터셉터만 동작하므로 빈을 하나만 등록했습니다.

바로 아래코드인 <Interceptors> 태그부터 설정코드입니다

<Interceptors>태그 안에는 여러 컨트롤러마다 설정할 인터셉터를 등록하게됩니다. 지금은 1개의 인터셉터만 등록되있는거라고 보시면 됩니다.

<interceptor>태그로 인터셉터를 본격적으로 설정합니다.

이곳에서는 어떤 인터셉터 클래스를 참조하여 동작할것인지 와 어떤 매핑주소를 입력했을때 동작할것인지 에 대한 설정을 등록합니다.

 

 

 

[ /test1 ]

주소창에 test1을 입력하였을때, test1에 들어갈때 인터셉터가 1회 작동하게 됩니다.

디스패처로부터 컨트롤러로 접근하기 전 인터셉터가 작동하면서 preHandle()메서드가 작동하고 메서드의 return을 true로 해줬기 때문에 인터셉터를 통과하여 컨트롤러로 진입하게 됩니다.

통과후 작업 수행을 마친 뒤 요청이 뷰페이지로 응답하기 위해서 다시 디스패처로 돌아가게되는데 이때 다시 인터셉터의 postHandle에 걸립니다.

postHandle에서 model객체에 "data"가 들어있는지 확인 후 없으므로 if문 실행없이 멈춥니다

뷰페이지의 ${data}에는 아무것도 출력되지 않게됩니다.

 

[ /test2 ]

주소창에 /test2라고 입력하거나 test1페이지에서 하이퍼링크를 통해 /test2로 접근하게 된다면 인터셉터가 총 2회 작동하게 됩니다.

디스패처로부터 컨트롤러로 접근하기 전 인터셉터가 작동하여 test1과 마찬가지로 preHandle()메서드 동작 후 컨트롤러로 진입하게 됩니다.

그리고 다시 응답요청으로 인해 뷰로 돌아오는 과정에서 postHandle()에 걸립니다.

이것이 test1과 같은 인터셉터 1회 사이클이며, postHandle에서 model객체에 "data"가 들어있기때문에 if문이 실행되면서 세션에 "data"를 담게됩니다.

그리고 redirect로 /test1을 재요청합니다. 이때 재요청되면서 인터셉터 사이클이 1회 더 작동하게 되는것이죠.

 

 

인터셉터 빈등록 설정과 함께 작동 과정을 다시 한번 설명하겠습니다

<mapping path="/test1>"에 등록된 경로에 의해서
testInterceptor가 작동해서 처음 진입할 때 preHandle이 작동하여서 log발생
그리고 return true로 그냥 진입시켜줫습니다.
처리하고 다시 나올때 postHandle이 한번 작동하였고 
ModelAndView에서 getModel을 하고있습니다.
view객체와 model객체중 model만꺼내와서 data라는애를 뒤져밨더니 test1에는 데이터가 없었습니다.
데이터가 null이나왔으므로 if문이 동작을 하지않고 끝나버렸지만

/test2가 작동되엇을때는
preHandle() 1회발생 후 postHandle()에서 ModelAndView의 model에 접근하여 data라는 애를 뒤져봤더니 존재합니다...
if문이 동작하여서 data를 data키이름에 실어 세션에 저장한 후
redirect로 다시 처음페이지로 이동하게되니 /test1의 preHandle과 postHandle사이클이
1회 더 돌게된것입니다.

추가로 세션에 데이터를 담았기때문에 redirect된 test1에서도 session에담긴 "data"의 문자열 Hello World! 라는 데이터를 출력해 주게 된것이구요. 

728x90
반응형