22. 스프링 프레임워크 - 인터셉터[자바 웹을 다루는 기술]
인터셉터(Interceptor)란?
인터셉터는 중간에서 가로챈다는 뜻입니다. 사전적 의미를 생각하며 스프링 인터셉터의 기능을 생각해 보자면
Client(브라우저)의 Request를 Controller에서 받아 실행 하기 전에 중간에서 가로채는 역할을 하고
Controller 실행 후 DispacherServlet이 View로 보내기 전에 가로채는 역할을 합니다.
스프링 HandlerInterceptor 클래스의 메서드
메서드 | 기능 |
preHandle() | 컨트롤러 실행 전 호출 됩니다. |
postHandle() | 컨트롤러 실행 후 DispathcerServlet이 뷰로 보내기 전에 호출 됩니다. |
afterCompletion() | 뷰까지 수행하고 나서 호출 됩니다. |
servlet-context.xml
<?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:mvc="http://www.springframework.org/schema/mvc" //<mvc:~> 캐그를 사용하기 위해 추가
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
..................
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/test/*.do"/>
<mvc:mapping path="/*/*.do"/>
<beans:bean class="com.myspring.pro28.ex05.LocaleInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
/test/*.do 와 .do 끝나는 모든 요청에 대해서 인터셉터가 실행 되도록 설정 합니다.
message-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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--스프링의 SessionLocaleResolver 클래스를 이용해 locale 정보를 세션에 저장해서 사용 -->
<!--패키지 locale에서 message.properties를 읽어 드림 -->
<!--properties 파일이 변경되었는지 확인하는 주기를 지정, 60초 간격으로 지정 -->
<!-- 메시지 파일로 프로퍼티 형식 사용을 위한 messageSource 구현체 클래스 빈 설정 -->
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver" />
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:locale/messages</value>
</list>
</property>
<property name="defaultEncoding" value="UTF-8"/>
<property name="cacheSeconds" value="60"/>
</bean>
</beans>
다국어 기능과 관련된 빈과 메시지 파일을 읽어 들이는 message-context.xml을 작성 합니다.
locale에서 message.properties 파일을 읽어 들입니다.
다국어를 정리한 프로퍼티스 파일 생성
LocaleInterceptor.java
package com.myspring.pro28.ex05;
..................
//사용자 정의 인터셉터는 반드시 HandlerInterceptorAdapter를 상속 받아야 함
public class LocaleInterceptor extends HandlerInterceptorAdapter{
@Override
//컨트롤러 실행 전 호출
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HttpSession session = request.getSession();
//브라우저에서 전달한 locale 정보를 가져옵니다.
String locale = request.getParameter("locale");
//최초 요청시 locale을 한국어로 설정
if(locale==null) locale="ko";
//LOCALE 속성 값을 세션에 저장, SessionLocaleResolver가 사용할 수 있게 함
session.setAttribute("org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE", new Locale(locale));
return true;
}
//컨트롤러 실행 후 호출
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
//뷰(JSP)를 수행한 후 호출
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
LocaleController.java
package com.myspring.pro28.ex05;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class LocaleController {
@RequestMapping(value="/test/locale.do", method=RequestMethod.GET)
public String locale(HttpServletRequest request,
HttpServletResponse response) throws Exception{
System.out.println("localeController 입니다.");
//컨트롤러는 뷰이름만 반환
return "locale";
}
}
locale.jsp로 반환하는 controller를 작성 합니다.
locale.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<c:set var="contextPath" value="${pageContext.request.contextPath }"/>
<%
request.setCharacterEncoding("utf-8");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!--spring:message 이용해 code속성에 프로퍼티 파일의 site.title 값을 표시 -->
<title><spring:message code="site.title" text="Member Info"/></title>
</head>
<body>
<!-- 한국어, 영어를 요청 -->
<a href="${contextPath }/test/locale.do?locale=ko">한국어</a>
<a href="${contextPath }/test/locale.do?locale=en" >ENGLISH</a>
<h1><spring:message code="site.title" text="Member Info"/></h1>
<!-- 프로퍼티 site.name에 해당하는 값을 표시, 프로퍼티 name에 해당하는 값 표시 -->
<p><spring:message code="site.name" text="no name"/> :
<spring:message code="name" text="no name"/></p>
<p>
<spring:message code="site.job" text="no job"/> :
<spring:message code="job" text="no job"/></p>
<input type="button" value="<spring:message code='btn.send'/>" />
<input type="button" value="<spring:message code='btn.cancel'/> "/>
<input type="button" value="<spring:message code='btn.finish' /> "/>
<!--spring:message 태그를 이용해 프로퍼티 bin.send를 버튼 이름으로 설정 -->
</body>
</html>
<spring:message> 태그를 사용 할 수 있도록 <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
를 지정 해줍니다.
<spring:message> code 속성에 프로퍼티스 파일의 site.title 값을 표시합니다.
그리고 한국어, 영어 요청에 따라 controller에 매개변수를 전달해 controller를 실행하고 뷰로 다시 반환합니다.
<spring:message code="properties의 키" text="기본값" />
인터셉터 사용해서 request명에서 뷰이름을 가져오기
package com.myspring.pro27.member.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 ViewNameInterceptor extends HandlerInterceptorAdapter{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String viewName = getViewName(request);
request.setAttribute("viewName", viewName);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
private String getViewName(HttpServletRequest request) throws Exception {
String contextPath = request.getContextPath();
String uri = (String) request.getAttribute("javax.servlet.include.request_uri");
if (uri == null || uri.trim().equals("")) {
uri = request.getRequestURI();
}
int begin = 0;
if (!((contextPath == null) || ("".equals(contextPath)))) {
begin = contextPath.length();
}
int end;
if (uri.indexOf(";") != -1) {
end = uri.indexOf(";");
} else if (uri.indexOf("?") != -1) {
end = uri.indexOf("?");
} else {
end = uri.length();
}
String viewName = uri.substring(begin, end);
if (viewName.indexOf(".") != -1) {
viewName = viewName.substring(0, viewName.lastIndexOf("."));
}
if (viewName.lastIndexOf("/") != -1) {
viewName = viewName.substring(viewName.lastIndexOf("/",1), viewName.length());
}
return viewName;
}
}
아래 getViewName()을 request에 viewName으로 바인딩하여 컨트롤에서 request.getAttribute("viewName");을 사용합니다.
#마무리
인터셉터를 통해 Controller에 도달하기 전에 뭔가 기능을 실행해야 하는경우가 있습니다.
또한 AOP와도 같이 사용할 수 있으니 응용해 보시기 바랍니다.