today_is

[ spring ] Interceptor 본문

spring

[ spring ] Interceptor

ye_rang 2024. 1. 1. 23:11

오늘의 목표

Interceptor 를 만들어서 일부 기능은 조건에 부합하는 사용자만 이용할 수 있도록 제한을 걸어보자


 

 

 

인터셉터가 필요한 이유

ex) 로그인 필요한 컨트롤러 함수에는 같은 코드를 일괄 적용 가능 

if(session.getAttribute("login") == null) {
return "redirect:/member/login";
}

그러나, 컨트롤러 함수마다 반환형이 서로 다르고 
HttpSession 을 매개변수로 추가해줘야 하기 때문에 번거롭다
메뉴의 개수가 늘어날수록 작업은 점점 더 번거로워지기 때문에

이 부분을 담당할 인터셉터가 필요하다. 



 

 

Handle 컨트롤러의 실행함수
PreHandle 컨트롤러 실행하기 전에 작동하는 것
PostHandle 컨트롤러가 끝나고 jsp로 넘어가기 전에 실행
Aftercompletion 모든 것을 완료하기 직전



LoginInterceptor

: 로그인 되어있는지 판별

 

[ 로그인 인터셉터를 적용할 수 있는 곳 ]

마이페이지 / 게시글 작성 / 로그아웃 등등

 

 

 

 참고사항

스프링 4.0 에서는 exnteds HandlerInterceptorAdapter
스프링 5에서는 implements HandlerInterceptor

HandlerInterceptor 는 인터페이스이지만, 내부함수가 default 키워드로 처리되어 있음
인터페이스에서 default 함수는 바디를 가질 수 있다
미구현된 메서드만 구현하면 된다 
추상 메서드가 아니라서 모든 메서드를 의무적으로 오버라이딩 할 필요는 없다 

 

 

PreHandle

package com.itbank.interceptor;

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

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class LoginInterceptor implements HandlerInterceptor {
	
//	PreHandle :	요청이 컨트롤러에 도착하기 전에 요청을 가로채서 작업을 수행
//	반환값에 따라 예정된 내용을 그대로 처리할지, 다른 내용을 수행할지 결정한다
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
    	Object handler) throws Exception {
	
		System.out.println("1. PreHandle");
		HttpSession session = request.getSession();
		
		String url = request.getRequestURL().toString();
		System.out.println("url : " + url);
		
		if(session.getAttribute("login") == null) {	//	만약 세션에 로그인이 없으면 
			String cpath = request.getContextPath();
			response.sendRedirect(cpath + "/member/login?url=" + url);
			System.out.println("로그인 상태가 아니므로, 로그인 페이지로 이동합니다.\n");
			return false;	//	진행 중지
			//	진행 중지되고 나서는 login 페이지로 이동 
		}
		return true;
	}

 

PostHandle

//	컨트롤러의 처리가 끝났고, jsp 로 넘어가기전에 작동한다
//	jsp로 forword 가 이루어지기 전에, request, cookie, session 등에서 필요한 값을 확인하고 판별하여
//	ModelAndView 를 이용하여 특정 데이터를 넣어주는데 활용할 수 있다
//	header.jsp 를 사용할수도 있으나, 모든 페이지에 영향을 주기 때문에 일부페이지에만 적용하기 쉽지않다 (== 그래서 PostHandle 을 쓰자!)

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response,
    	Object handler,ModelAndView mav) throws Exception {
		
		System.out.println("2. postHandle");
		mav.addObject("test1", "Hello, Interceptor");	
	}

 

afterCompletion

//	사용자에게 jsp의 화면이 모두 전달되고, 응답이 완료된 후에 작동함 
//	만약, 예외가 발생한다면 로그에 기록하거나 알림을 처리할 수도 있다.
		
//	afterCompletion 대신에 사용할 수 있는 것
//	1) @ExceptionHandler, @ControllerAdvice 는 예외를 처리하는데에 특화되어있음 
//	2)  Log4j 와 같은 로그 라이브러리도 있다 

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, 
    	Object handler, Exception ex) throws Exception {
		
		System.out.println("3. afterCompletion");
	}
	
}

 

 




AdminInterceptor

: 관리자 인터셉터, 관리자의 로그인이 적용되어있는지 판별

[ 관리자로 로그인이 되어있는 상태 ] 계속 진행

[ 관리자로 로그인이 되어있지 않음 ] alert.jsp 로 넘겨서 경고창 띄워주고 대문페이지로 리다이렉트하기 

 

 

 

 유의할 점 
AdminInterceptor 도 spring bean 으로 등록해줘야한다 !

package com.itbank.interceptor;

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

import org.springframework.web.servlet.HandlerInterceptor;

import com.itbank.model.MemberDTO;

public class AdminInterceptor implements HandlerInterceptor{
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
    		Object handler) throws Exception {

		System.out.println("1. 관리자 계정 로그인 확인용 : preHandle");
		
		HttpSession session = request.getSession();
		
		MemberDTO dto = (MemberDTO) session.getAttribute("login");
		
		if(dto == null || dto.getUserid().equals("admin") == false) {
			
			RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/member/alert2.jsp");
			
			request.setAttribute("url", "/");
			request.setAttribute("msg", "관리자 계정만 접근가능");
			rd.forward(request, response);
		
			return false;
		}
		return true;
	}
}

 

 

 

 코드 해석 

 

로그인이 되어있지 않거나(dto == null) , 로그인된 계정의 userid 가 admin 이 아니라면 

->   if(dto == null || dto.getUserid().equals("admin") == false) {

 

 

alert2.jsp 로 보낸다
->   RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/member/alert2.jsp");

 

 

alert2 에서 '관리자 계정만 접근가능' 이라는 경고창을 보여주고, alert 을 확인했다면 대문페이지로 보낸다 
->   request.setAttribute("url", "/");
        request.setAttribute("msg", "관리자 계정만 접근가능");

 

 

alert2.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="../header.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<script>
	const url = '${url}'
	const msg = '${msg}'
	const cpath = '${cpath}'
	
	if(url == '') {
		alert('실패')
		location.href = cpath 
	}
	else {
		alert(msg)
		location.href = cpath + url
	}


</script>

</body>
</html>

study_review

항상 로그인이 되어있지 않다면 login페이지로 리다이렉트 하도록 코드를 복붙해서 추가했었는데

인터셉터를 이용하면 현재 상태에 따라, 사용자에게 안내할 수 있어서 좀 더 편리한것 같다

 

 

그렇지만 인터셉터는 개발 도중에 진행하는 것이 비효율적이라고 한다.

아직 기능이 제대로 구현되지 않은채로 인터셉터를 걸어버리면

테스트를 진행할때 너무 불편하기 때문이다.

 

 

그래서 꼭 개발 마지막 단계에 진행해야한다. 

미리 인터셉터를 어디에 적용시킬지 생각하면서 개발에 임하면

나중에 수월할 것 같다는 생각이 든다 !