본문 바로가기

JAVA/Spring

Spring Interceptor

반응형

Spring MVC Interceptor (스프링 MVC의 인터셉터)

스프링을 이용해서 사용자의 단순 로그인을 처리하는 가장 간단한 방법은 Servlet의 Filter와 유사한 인터셉터(Interceptor)를 활용하는 방법


인터셉터는 웹 애플리케이션 내에서 특정한 URI 호출을 말 그대로 가로채는 역할을 한다.
이를 활용하면 로그인한 사용자만 사용할 수 있는 기능을 제어할 수 있기 때문에 기존 컨트롤러의 로직을 수정하지 않고도, 사전이나 사후에 제어가 가능하다.

Filter와 Interceptor의 공통점
Servlet 기술의 Filter와  Spring MVC의 HandlerInterceptor는 특정 URI에 접근할 때 제어하는 용도로 사용
설정은 web.xml에 사용하는 필터의 설정과 유사한 부분이 많다.

Filter와 Interceptor의 차이점
Filter는 동일한 웹 애플리케이션의 영역 내에서 필요한 자원들을 활용
Interceptor는 스프링에서 관리되기 때문에 스프링 내의 모든 객체(빈)에 접근이 가능하다는 차이
Filter의 경우 웹 애플리케이션 내에서 동작하므로, 스프링의 Context에 접근하기 어렵다
Interceptor의 경우 Spring Context 내에서 존재하므로 Context내의 모든 객체를 활용 할 수 있다.
HandlerInterceptor의 경우 스프링의 빈으로 등록된 컨트롤러나 서비스 객체들을 주입받아서 사용할 수 있기 때문에 기존의 구조를 그대로 활용하면서 추가적인 작업이 가능하다.

AOP의 Advice와 HandlerInterceptor의 가장 큰 차이는 파라미터의 차이
Advice의 경우 JoinPoint 나 ProceedingJoinPoint 등을 활용해서 호출 대상이 되는 메소드의 파라미터 등을 처리하는 방식
HandlerInterceptor는 Filter와 유사하게 HttpServletRequest, HttpServletResponse를 파라미터로 받는 구조
일반적인 경우 Controller에서 DTO(Data Transfer Object)나 VO(Value Object) 타입을 주로 파라미터로 활용하고,
Servlet API에 해당하지HttpServletRequest, HttpServletResponse를 활용하는 경우는 그다지 많지 않다.
HandlerInterceptor는 기존의 컨트롤러에서는 순수하게 필요한 파라미터와 결과 데이터를 만들어 내고, 인터셉터를 이용해서 웹과 관련된  처리를 도와주는 역할를 한다.

HandlerInterceptor 메소드
preHandler(request, response, handler) - 지정된 컨트롤러의 동작 이전에 가로채는 역할로 사용
postHandler(request, response, handler, modelAndView) - 지정된 컨트롤러의 동작 이후에 처리 Spring MVC의 Front Controller인 DispatcherServlet이 화면을 처리하기 전에 동작
afterHandler(reqeust, response, handler, exception) - DispatcherServlet의 화면처리가 완료된 상태에서 처리

대부분은 preHandler()을 이용해서 로그인에 대한 처리를 진행하는 것이 일반적이다.

HandlerInterceptorAdapter 클래스
HandlerInterceptor는 인터페이스로 정의되어 있지만 HandlerInterceptorAdapter는 인터페이스를 구현한 추상 클래스로 설계되어 있다.
일반적으로 디자인 패턴에서 Adapter라는 용어가 붙으면 특정 인터페이스를 미리 구현해서 사용하기 쉽게 하는 용도인 경우가 많다.
HandlerInterceptorAdapter 역시 HandlerInterceptor를 쉽게 사용하기 위해서 인터페이스의 메소드를 미리 구현한 클래스이다.


public class SampleInterceptor extends HandlerInterceptorAdapter {

servlet-context.xml 인터셉터 설정

<beans:bean id="sampleInterceptor" class="org.zerock.interceptor.SampleInterceptor" ></<beans:bean >

<interceptors>

<interceptor>

<mapping path="/doA" />

<mapping path="/doB" />

<beans:ref bean="sampleInterceptor" />

</interceptor>

</interceptors>

인터셉터의 설정은 Interceptors 태그를 이용해서 설정
XML 네임스페이스에 spring mvc 관련 설정이 추가해야한다.
각 인터셉터의 <mapping>에는 원하는  URI를 지정한다.
이러한 설정은 web.xml 필터나 servlet의 설정과 동일하므로, 필요한 경로를 직접 지정하거나 '**', '*'와 같은 패턴을 적용해 줄수 있다.

HomeController 

@RequestMapping(value="/doA", method=RequestMethod.GET)

public String doA(Locale locale, Model model) {

System.out.println("doA");

return "home";

}


@RequestMapping(value="/doB", method=RequestMethod.GET)

public String doB(Locale locale, Model model) {

System.out.println("doB");

model.addAttribute("result", "doB result");

return "home";

}


SampleInterceptor

public class SampleInterceptor extends HandlerInterceptorAdapter {

public void postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

System.out.println("post Handler");

}


public boolean preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

System.out.println("pre handle");

return true;

}

}

preHandler()의 경우 리턴 타입이 boolean으로 설계하여 다음 Interceptor나 대상 컨트롤러를 호출하도록 할 것인지를 결정한다.


인터셉터의 request, response 활용방법

  public boolean preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

System.out.println("pre handle");

HadlerMethod method = (HandlerMethod) handler;'

Method  methodObj = method.getMethod();


System.out.println("Bean: "+ method.getBean());

System.out.println("Method: "+ methodObj);


return true;

}

preHandler()의 경우 세 개의 파라미터를 사용하는데, HttpServletRequest, HttpServletResponse, Object handler로 구성된다.
마지막의 handler는 현재 실행하려는 메소드 자체를 의미하는데, 이를 활용하면 현재 실행되는 컨트롤러를 파악하거나 추가적인 메소드를 실행하는 등 작업이 가능하다.


  public void postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

System.out.println("post Handler");


Object result = modelAndView.getModel().get("result");


if(result != null){

request.getSession().setAttribute("result", result);

response.sendRedirect("/doA");

}

}

postHandler()의 경우 컨트롤러 메소드의 실행이 끝나고 아직 화면 처리는 안된 상태이므로 필요하다면 메소드의 실행 이후에 추가적인 작업이 가능하다.예를 들어 특정한 메소드의 실행결과를 HttpSession 객체에 같이 담아야 하는 경우를 생각해볼수 있다.
컨트롤러에서는  Model 객체에 결과 데이터를 저장하고 인터셉터의 postHandler()에서 이를 이용해 HttpSession에 결과를 담는 다면, 컨트롤러에서 HttpSession을 처리할 필요가 없게된다.
컨트롤러에서 result 변수가 저장되었다면 HttpSession 객체에 이를 보관하는 방법으로 사용

컨트롤러의 코드에서 '/doB'를 호출하면 'result' 라는 이름으로 하나의 문자열이 보관된다.
이후 postHandler()에서 'result' 변수가  ModelAndView에 존재하면 이를 추출해서 HttpSession에 추가한다.
HomeController에서 '/doB'를 먼저 호출해서 HttpSession에 'result'라는 이름을 보관후 '/doA' 로 redirect를 수행한다.


컨트롤러에서는 로그인 처리 후 결과를 반환하고, 인터셉터를 이용해서 HttpSession에 로그인이 필요한 객체를 보관하는 형태로 작성하면 컨트롤러에서 직접 HttpSession 등의 API를 사용하지 않는 코드를 만들수 있다.



반응형

'JAVA > Spring' 카테고리의 다른 글

Spring login with cookie  (0) 2017.12.14
Spring Interceptor HttpSession Login  (0) 2017.12.13
Spring Transaction  (0) 2017.11.27
Spring AOP  (0) 2017.11.21
RestController  (0) 2017.11.20