인터셉터(Interceptor)
ineterceptor : 클라이언트의 요청 전후에 특정 작업을 처리하고자 할때 사용하는 기능
매개변수 : HttpServletRequest, HttpServletResponse
용도 : 로그인 처리, pc웹/모바일웹 분기 처리 등
filter ex) web.xml에서 설정한 한글처리를 위한 인코딩 필터
filter는 선처리만된다. AOP는 @Before/ After / Around
filter와 AOP 사이쯤 있는게 Interceptor
인터셉트도 요청 전후에 특정 작업 처리가 가능. AOP의 arround와 비슷한 성격
인터셉트는 url단위 (설정한 url이 실행될 때 실행) , AOP는 메서드 단위(설정한 메서드가 호출될 때 실행)
html 페이지는 웹서버에서 별도의 처리를 하지 않고 그대로 클라이언트에게 전달
jsp페이지는 JspServlet을 경유하여 html로 변환된 후 클라이언트에게 전달
서블릿은 DefaultServlet을 경유하여 전달되는데
Spring Framework에서는 DispatcherServlet을 경우하여 처리됨
실행 순서 : Filter > DispatcherServlet > Interceptor > AOP
실습 예제
1. interceptor.SampleInterceptor.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | package com.example.spring02.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; // HandlerInterceptorAdapter 를 상속받음(추상클래스) public class SampleInterceptor extends HandlerInterceptorAdapter { //로깅을 위한 변수 private static final Logger logger = LoggerFactory.getLogger(SampleInterceptor.class); //선처리 @Override public boolean preHandle(HttpServletRequest request , HttpServletResponse response, Object handler) throws Exception { logger.info("pre handle..."); return true; //true이면 계속 진행, false이면 멈춤 } //후처리 @Override public void postHandle(HttpServletRequest request , HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { logger.info("post handle..."); } } | cs |
클래스 생성시
HandlerInterceptorAdaptor 상속하여 preHandle / postHandle 메서드 오버라이딩
preHandle은 요청 전 경유 코드, postHandle은 요청 후 경유 코드
2. servlet-context.xml 인터셉터 관련 설정
먼저 인터셉터를 bean으로 설정
<beans:bean id="인터셉터의 아이디" class = "인터셉터의 경로" />
어떤 url을 호출했을 때 인터셉트를 작동시킬 것인지 설정
1 2 3 4 5 6 | <interceptors> <interceptor> <mapping path="/shop/**" /> <beans:ref bean="인터셉터의 아이디 " /> </interceptor> </interceptors> | cs |
servlet-context.xml 인터셉터 관련 설정
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <!-- 인터셉터 빈을 등록 --> <beans:bean id="sampleInterceptor" class="com.example.spring02.interceptor.SampleInterceptor"> </beans:bean> <beans:bean id="loginInterceptor" class="com.example.spring02.interceptor.LoginInterceptor"> </beans:bean> <beans:bean id="adminInterceptor" class="com.example.spring02.interceptor.AdminInterceptor" /> <!-- 인터셉터 호출을 위한 url mapping --> <interceptors> <interceptor> <mapping path="/shop/**" /> <beans:ref bean="sampleInterceptor" /> </interceptor> <interceptor> <mapping path="/board/write.do" /> <mapping path="/board/insert.do" /> <mapping path="/board/update.do" /> <mapping path="/board/delete.do" /> <mapping path="/shop/cart/list.do"/> <mapping path="/shop/cart/insert.do"/> <beans:ref bean="loginInterceptor"/> </interceptor> <interceptor> <mapping path="/pdf/list.do"/> <mapping path="/shop/product/write.do"/> <mapping path="/shop/product/insert.do"/> <mapping path="/chart/**" /> <mapping path="/jchart/**" /> <beans:ref bean="adminInterceptor" /> </interceptor> </interceptors> | cs |
path(url)에 /shop/이 들어가있으면 아이디가 sampleInterceptor인 인터셉터를 실행하게하는 맵핑 코드
view/include/session_check.jsp
인터셉터를 사용하지 않고 세션의 존재 여부를 체크할 경우
세션을 확인하여 로그인 상태가 아닐 경우 로그인 페이지로 넘겨주는 코드
1 2 3 4 5 6 | <c:if test="${sessionScope.admin_userid == null}"> <script> alert("로그인하신 후 사용하세요."); location.href="${path}/admin/login.do" </script> </c:if> | cs |
인터셉터를 통해 로그인 체크하기
1. LoginInterceptor.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | package com.example.spring02.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; //HandlerInterceptorAdapter 추상클래스 상속 // preHandle(), postHandler() 오버라이딩 public class LoginInterceptor extends HandlerInterceptorAdapter { //메인 액션이 실행되기 전 @Override public boolean preHandle(HttpServletRequest request , HttpServletResponse response, Object handler) throws Exception { //세션 객체 생성 HttpSession session=request.getSession(); //세션이 없으면(로그인되지 않은 상태) if(session.getAttribute("userid") == null) { //login 페이지로 이동 response.sendRedirect(request.getContextPath() +"/member/login.do?message=nologin"); return false; //메인 액션으로 가지 않음 }else { return true; //메인 액션으로 이동(매핑된 url) } } //메인 액션이 실행된 후 @Override public void postHandle(HttpServletRequest request , HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { super.postHandle(request, response, handler, modelAndView); } } | cs |
2. servlet-context에서 url매핑 추가
CartController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | @RequestMapping("list.do") public ModelAndView list(HttpSession session, ModelAndView mav) { Map<String, Object> map = new HashMap<>(); // 세션변수 확인 String userid = (String) session.getAttribute("userid"); //if (userid != null) { // 로그인한 경우 List<CartDTO> list = cartService.listCart(userid); // 장바구니 합계 계산 int sumMoney = cartService.sumMoney(userid); // 배송료 계산 int fee = sumMoney >= 30000 ? 0 : 2500; map.put("sumMoney", sumMoney); // 장바구니 금액 합계 map.put("fee", fee); // 배송료 map.put("sum", sumMoney + fee); // 총합계금액 map.put("list", list); // 맵에 자료 추가 map.put("count", list.size()); mav.setViewName("shop/cart_list"); // jsp 페이지 이름 mav.addObject("map", map); // jsp에 전달할 데이터 return mav; //} else { // 로그인하지 않은 경우 userid <- null // return new ModelAndView("member/login", "", null); //} } | cs |
로그인하지 않은 경우 로그인 페이지로 보내는 내용의 코드 모두 주석처리
//로그인하지 않은 경우를 따지는 코드가 포함됐던 메서드와 매핑된 url 모두 인터셉트와 맵핑시킴
+추가)
1 2 3 4 5 6 | <http auto-config="true" use-expressions="true"> <intercept-url pattern="/member/**" access="hasAnyRole('ROLE_MEMBER','ROLE_ADMIN')"/> <intercept-url pattern="/user/**" access="hasAnyRole('ROLE_USER','ROLE_MEMBER','ROLE_ADMIN')"/> <intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')"/> <intercept-url pattern="/**" access="permitAll"/> </http> | cs |
<intercept-url> 태그를 이용하여 pattern 속성의 url 에 access 속성의 권한을 설정했다. /member/ 경로는 정회원, 관리자가 접근할 수 있고, /user/ 경로는 준회원, 정회원, 관리자가 접근할 수 있고, /admin/ 경로는 관리자만 접근할 수 있다. 그리고 모든 경로(/**)는 로그인 하지 않은 이용자도 접근할 수 있다.
<intercept-url> 태그를 사용할 때 반드시 주의해야할 점이 있다. 경로 설정을 하게 되면 태그를 하나가 아닌 여러개를 설정하게 된다. 여러개가 설정할 경우, 설정된 순서대로 위에서부터 매칭되어진다. 따라서 태그의 설정 순서가 중요하다. 태그의 순서로 인해서 꼬여버리거나 무한 루프가 돌 수 있기 때문이다. 가장 특수한 경우를 위에 놓고 아래쪽으로 갈 수록 일반적인 경우를 둬야 한다. 즉, 구체적인 패턴을 먼저 설정해야 한다. /admin/** 패턴과 /** 패턴를 보면, /admin/** 패턴은 admin 디렉토리 밑에 있는 모든 디렉토리와 파일을 의미하고, /** 패턴은 모든 디렉토리와 파일을 의미한다. 즉, /admin/** 은 /**보다 더 구체적인 패턴이라는 뜻이다. 그럼 /admin/** 패턴을 /** 보다 위에 설정해주어야 한다. 만약 /** 패턴을 먼저 설정해버리면 모든 url이 /** 패턴을 만족하게 되고, admin 하위 디렉토리를 가르켜도 /** 패턴을 먼저 매칭시켰기 때문에 admin이 아닌 권한들도 admin 디렉토리에 접근이 가능해져 버린다. 따라서 구체적인 패턴이 먼저 설정되어야 한다. 직접 보고 싶다면 위의 패턴에서 /member/** 패턴과 /user/** 패턴의 위치를 바꿔서 실행시키면 알 수 있다. user 권한이 member 디렉토리에 접근하는 것을 확인할 수 있다.
출처: https://to-dy.tistory.com/75 [todyDev]
'Spring > study' 카테고리의 다른 글
REST API (이후에 다시 정리) (0) | 2019.07.01 |
---|---|
spring 16강 자바스크립트 난독화, Proguard를 이용한 자바 코드 난독화 (0) | 2019.07.01 |
spring 14강 AOP와 트랜잭션 처리 실습 (0) | 2019.06.28 |
spring 13강 AOP의 개요, 로그수집 예제 (0) | 2019.06.27 |
http와 https의 차이점 (0) | 2019.06.27 |