본문 바로가기
멀티캠퍼스 풀스택 과정/백엔드

Spring:13 Interceptor(인터셉터) -5

by 이쟝 2022. 3. 19.

인터셉터 ( Interceptor )

컨트롤러에 들어오는 요청 HttpRequest와 컨트롤러가 응답하는 HttpResponse를 가로채는 역할을 한다. 
즉, 특정 url로 요청 시 Controller로 가는 요청을 가로채는 역할을 한다. 

 

만약 인터셉터를 이용하지 않고, 로그인 처리를 한다면, 게시물을 작성, 게시물 수정, 게시물 삭제 등 모든 요청마다 Controller에서 session을 통해 로그인 정보가 남아 있는지를 확인하는 코드를 중복해서 입력해야 할 것이다. 

하지만 인터셉터를 이용하면, A, B, C 작업(A,B,C 경로로 요청)을 할 경우에는 ~~ Interceptor를 먼저 수행해 session에서 로그인 정보가 있는지 확인해 주는 역할을 한다면, 중복 코드가 확 줄어들 수 있을 것이다.

인터셉터 구현하기

Spring에서 Interceptor의 구현은 HandlerInterceptor(Interface)HadlerInterceptorAdapter(Abstract class)로 구현할 수 있다. 

HandlerInterceptorAdapter Abstract Class는 HandlerInterceptor Interface를 상속받아 구현됨

위 두가지 중 하나를 구현하는 Class를 생성한 후, DispatcherServlet의 Context(servlet-context.xml)에 작성 Interceptor Class를 Bean 등록하고, 적용 Url을 명시해주면 된다.

구현 메서드

1. preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

Controller(RequestMapping 선언 Handler) 실행 직전에 동작하는 메서드이다. 
return 값이 true일 경우 정상적으로 진행이 되고,
false일 경우 실행 종료 -> Controller 진입 X
Parameter 중 Object handler는 HandlerMapping이 찾은 Controller Class 객체이다.

2. postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)

Controller 진입 후 View가 Rendering 되기 전 수행된다.
Parameter 중 ModelAndView modelAndView를 통해 화면 단에 들어가는 Data 등의 조작이 가능하다.

3. afterComplete(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

Controller 진입 후 View가 정상적으로 Rendering 된 후 수행된다.

4. afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)

Servlet 3.0부터 비동기 요청이 가능해지며 생겨난 method로,
비동기 요청 시 PostHandle와 afterCompletion method를 수행하지 않고 이 메서드를 수행한다.

1. 환경설정

먼저 pox.xml에 spring-web Dependency 가 존재하는지 확인한다. ( Maven Dependencies에 이미 spring-web-5.2.19.RELEASE.jar가 있다. )

1.HandlerInterceptor나 HandlerInterceptorAdapter를 구현하는 자신만의 Interceptor Class를 구현한다.

로그인이 되어있으면 OK 로그인이 되어있지 않으면 로그인 폼으로 이동한다. 

package com.mycampus.myappy.interceptor;

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

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class SigninInterceptor extends HandlerInterceptorAdapter {

	// 컨트롤러가 호출되기 전에 실행될 메서드
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		
		// false : 해당 컨트롤러로 이동한다. (로그인 폼을 response.sendRedirect로 할당)
		// true : 해당 컨트롤러로 이동한다. (원래 접속했던 주소로 이동)
		
		// request 객체에서 session객체를 얻어오기
		HttpSession session = request.getSession();
		
		// 로그인 상태를 구하기
		String logInStatus = (String)session.getAttribute("logInStatus");
		
		if(logInStatus!=null && logInStatus.equals("Y")) { // 로그인 되었을 떄
			return true; // 원래 접속했던 주소로 이동하기
		}else { // 로그인 되지 않았을 때 로그인 폼으로 이동
			response.sendRedirect(request.getContextPath()+"/member/signIn");
			return false;
		}
	}
}

 

2. DispatcherServlet의 context(servlet-context.xml) 파일에 Interceptor Class와 적용 URL을 명시한다.

servlet-context.xml을 복사해서 같은 폴더에 넣는다. intercept-context.xml이라고 이름을 임의로 지정한다.

intercept-context.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:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
	<!-- Interceptor 처리를 위한 컨트롤러 목록을 등록할 객체를 생성한다.namespaes에서 context, mvc를 추가한다. -->
	<mvc:interceptors>
		<mvc:interceptor>
			<mvc:mapping path="/board/bulletinBrdWrite"/>
			<mvc:mapping path="/board/boardDelete"/>
			<mvc:mapping path="/board/multiChkDel"/>
			<bean class="com.mycampus.myappy.interceptor.SigninInterceptor"/>
		</mvc:interceptor>
	</mvc:interceptors>
</beans>

web.xml 

dispatcherServlet에게 알리기 위해서 /WEB-INF/spring/appServlet/intercept-context.xml 를 추가해준다.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/Javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

	<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml</param-value>
	</context-param>
	
	<!-- Creates the Spring Container shared by all Servlets and Filters -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml
					     /WEB-INF/spring/root-context.xml
						 /WEB-INF/spring/appServlet/intercept-context.xml
			</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
		
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	
	<!-- include -->
	<jsp-config>
		<jsp-property-group>
			<!-- 모든 jsp 파일 -->
			<url-pattern>*.jsp</url-pattern> 
			<!-- 모든 JSP 파일의 상단에는 header.jspf를 include해라 -->
			<include-prelude>/include/header.jspf</include-prelude>
			<!-- 모든 JSP 파일의 하단에는 footer.jspf를 include해라 -->
			<include-coda>/include/footer.jspf</include-coda>
		</jsp-property-group>
	</jsp-config>
	
	<!-- Post방식 전송의 한글인코딩  -->
	<filter>
		<description></description>
		<display-name>SpringEncodeFilter</display-name>
		<filter-name>SpringEncodeFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	
	<filter-mapping>
		<filter-name>SpringEncodeFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

</web-app>