본문 바로가기
컴퓨터공학/스프링

Interceptor

by 유리병 2023. 12. 5.

목차


     

    Interceptor의 개념

    쇼핑몰 사이트를 만들 경우, 장바구니, 찜하기, 주문 페이지에 들어가려면 반드시 로그인이 되어있어야 한다. 

     

    이때 아래 코드와 같이 각 맵핑 메소드마다 session을 체크해 접속을 체크할 수도 있다.

    @GetMapping("/member/regist.do")
    public String regist(HttpSession sess) {
    	/* 로그인 여부 체크 */
    	if(sess.getAttribute("loginSess") == null) return null;
        
    	return "member/write";
    }

    그러나 이 경우 장바구니, 찜하기, 주문 페이지 등 로그인을 요구하는 모든 페이지에서 Session을 체크하는 코드를 추가해야 한다.

     

    이렇게 모든 메소드에 Session체크를 하는 부분을 다 코딩해 넣지 않고도 AOP개념을 활용해 Session을 체크하는 하나의 코드만 만든 후, 모든 요청이 들어오기 전에 먼저 Session을 체크한 후, 요청을 처리할 수 있게 하는 것이 Interceptor이다.

     

     

    Interceptor 만들기

    Interceptor클래스 만들기

    Interceptor클래스를 만든다. 

     

    Interceptor는 HandlerInterceptor인터페이스를 구현해 만든다.

    HandlerInterceptor 인터페이스의 3가지 메소드

    • preHandle() : url이 컨트롤러에 도달하기 전에 수행
    • postHandle() : url이 컨트롤러에 도달한 후에 수행
    • afterCompletion() : 뷰를 실행한 후에 수행

    Interface는 대개 preHandle()함수를 주로 사용한다.

    preHandle()함수에서 로그인 여부를 체크해 요청을 거절하면 요청은 컨트롤러에 도달하지 않는다.

     

    public class UserLoginInterceptor implements HandlerInterceptor {
    	@Override
    	public boolean preHandle(HttpServletRequest request, 
    				HttpServletResponse response, 
    				Object handler) throws Exception {
                    
            	/* session에서 login여부를 확인 */
    		HttpSession sess = request.getSession();
    		UserVO login = (UserVO)sess.getAttribute("loginInfo");
    		if (login == null) {
            		/* 로그인 정보가 없을 경우 경고를 띄우고 로그인 하는 곳으로 이동 */
    			response.setContentType("text/html; charset=utf-8");
    			PrintWriter out = response.getWriter();
    			out.print("<script>");
    			out.print("alert('로그인 후 사용가능합니다.');");
    			out.print("location.href='/user/login.do';");
    			out.print("</script>");
    			out.close();
    			return false; /* Controller로 이동 차단 */
    		}
    		return true;  /* 로그인 정보가 있을 경우 Controller로 이동 */
    	}
    }

     

     

    Interceptor Bean객체 등록

    Config파일에 Interceptor객체 등록

    	// 인터셉터
    	@Bean
    	public UserLoginInterceptor userLoginIntercepton() {
    		return new UserLoginInterceptor();
    	}

     

    Config파일에서 Interceptor 주입

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        	/* 빈 객체 주입 및 url 설정 */
    	registry.addInterceptor(userLoginIntercepton()) // 빈 객체 주입 
           		/* user 아래로 오는 모든 요청에 대해 로그인 여부를 검사하되 */
    		.addPathPatterns("/user/**")			
                   	/* 아래 요청들은 로그인 여부 검사에서 제외 */
    		.excludePathPatterns("/user/join.do")
    		.excludePathPatterns("/user/login.do")
    		.excludePathPatterns("/user/idCheck.do")
    		.excludePathPatterns("/user/emailCheck.do")
    		.excludePathPatterns("/user/regist.do");
    }

     

     

    여러개의 Interceptor Bean을 등록/설정하기

    아래 코드와 같이 registry에 여러개의 interceptor를 추가해주면 된다.

    // 인터셉터
    @Bean
    public UserLoginInterceptor userLoginIntercepton() {
    	return new UserLoginInterceptor();
    }
    @Bean
    public SellerLoginInterceptor sellerLoginIntercepton() {
    	return new SellerLoginInterceptor();
    }
    @Bean
    public CategoryInterceptor categoryInterceptor() {
    	return new CategoryInterceptor();
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    	// url 설정
    	registry.addInterceptor(userLoginIntercepton())
    		.addPathPatterns("/user/**")
    		.excludePathPatterns("/user/join.do")
    		.excludePathPatterns("/user/login.do")
    		.excludePathPatterns("/user/idCheck.do")
    		.excludePathPatterns("/user/emailCheck.do")
    		.excludePathPatterns("/user/regist.do");
    	
    	registry.addInterceptor(sellerLoginIntercepton())
    		.addPathPatterns("/seller/**")
    		.excludePathPatterns("/seller/login.do")
    		.excludePathPatterns("/seller/join.do")
    		.excludePathPatterns("/seller/idCheck.do")
    		.excludePathPatterns("/seller/emailCheck.do")
    		.excludePathPatterns("/seller/regist.do");
    	
    	registry.addInterceptor(categoryInterceptor())
    		.addPathPatterns("/")
    		.addPathPatterns("/user/**")
    		.addPathPatterns("/product/**");
    }

     

     

    Interceptor를 통해 jsp에 데이터 전달하기

    public class CategoryInterceptor implements HandlerInterceptor {
    	@Override
    	public boolean preHandle(HttpServletRequest request, 
    							HttpServletResponse response, 
    							Object handler)
    							throws Exception {
    		
            	/* Interceptor에서 request객체를 통해 데이터를 삽입 */
    		request.setAttribute("ProductCategoryVO", new ProductCategoryVO());
    		return true;
    	}
    }

    위와 같이 Interceptor를 통해 request객체에 데이터를 삽입할 경우 해당 Interceptor를 거쳐서 도달한 모든 jsp에서 해당 데이터를 사용할 수 있게된다.

     

    <!-- 
        Controller에서 따로 ProductCategoryVO를 보내지 않아도
        ${ProductCategoryVO}를 사용할 수 있다
    -->
    <li>
    <a>강아지</a>
    <ul>
    	<c:forEach var="category2" 
        	items="${ProductCategoryVO.category[0]}" varStatus="status">
    		<li>
    		<a href="/product/search.do?category1=0&category2=${status.index }">
    		${category2 }
    		</a>
    		</li>
    	</c:forEach>
    </ul>
    </li>
    
    <li>
    <a>고양이</a>
    <ul>
    	<c:forEach var="category2" 
        	items="${ProductCategoryVO.category[1]}" varStatus="status">
    		<li>
    		<a href="/product/search.do?category1=1&category2=${status.index }">
    		${category2 }
    		</a>
    		</li>
    	</c:forEach>
    </ul>
    </li>
    
    <li>
    <a>기타</a>
    <ul>
    	<c:forEach var="category2" 
        	items="${ProductCategoryVO.category[2]}" varStatus="status">
    		<li>
    		<a href="/product/search.do?category1=2&category2=${status.index }">
    		${category2 }
    		</a>
    		</li>
    	</c:forEach>
    </ul>
    </li>