서블릿 필터와 리스너란 뭘까?

목차

    1. 필터란?

    필터(Filter)는 서블릿이나 JSP에 요청이 도달하기 전에 요청과 응답을 가로채서 처리하는 컴포넌트이다. 필터는 요청을 수정하거나, 응답을 변경하거나, 로깅 및 인증 등의 작업을 수행할 수 있다.

    필터는 클라이언트와 자원사이에 여러개의 필터가 모여서 하나의 체인(Chain)을 형성할 수도 있다.

     

    WAS 서버에 필터를 설정하는 방법은 web.xml 파일에서 설정하거나 자바 코드측에 애노테이션을 사용하여 설정할 수 있는 방법이 존재한다.

     

    예시 코드 - web.xml 파일에 설정 가능

    <filter>
        <filter-name>LoggingFilter</filter-name>
        <filter-class>com.example.LoggingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>LoggingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

     

    예시 코드 - java 파일에 설정 가능

    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import java.io.IOException;
    
    @WebFilter("/*")
    public class LoggingFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            // 필터 초기화 작업
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            // 요청 전 처리
            System.out.println("Request received at " + new java.util.Date());
            chain.doFilter(request, response); // 다음 필터나 서블릿으로 요청 전달
            // 응답 후 처리
            System.out.println("Response sent at " + new java.util.Date());
        }
    
        @Override
        public void destroy() {
            // 필터 종료 작업
        }
    }

    필터의 주요 기능

    • 요청 및 응답의 전처리 및 후처리
    • 로깅 처리
    • 인증 및 권한 부여
    • 데이터 압축
    시나리오 코드 1
    프로젝트 생성 - filterListenerEx
    package com.tenco.filters;
    
    import java.io.IOException;
    
    import jakarta.servlet.Filter;
    import jakarta.servlet.FilterChain;
    import jakarta.servlet.FilterConfig;
    import jakarta.servlet.ServletException;
    import jakarta.servlet.ServletRequest;
    import jakarta.servlet.ServletResponse;
    
    /**
     * 1. Filter 구현 <br>
     * 2. URL 패턴 설정 (web.xml 파일에서 설정할 예정) <br>
     */
    public class IPBlockFilter implements Filter {
    	
    	// 차단할 IP 대역의 접두사
    	private static final String BLOCKED_IP_PREFIX = "192.168.0";
    	
    	@Override
    	public void init(FilterConfig filterConfig) throws ServletException {
    		System.out.println("IPBlockFilter 초기화 ");
    	}
    	
    	@Override
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    		
    		// 전처리 - 요청자의 IP를 확인
    		String remoteIP = request.getRemoteAddr();
    		System.out.println("Request from IP : " + remoteIP);
    		
    		// 차단 시킬 코드 작성
    		if (remoteIP.startsWith(BLOCKED_IP_PREFIX)) {
    			response.setContentType("text/plain; charset=UTF-8");
    			response.getWriter().println("Access Denied !!");
    			response.getWriter().println("ㅋㅋㅋ");
    			return;
    		}
    		chain.doFilter(request, response);
    	}
    }
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns="https://jakarta.ee/xml/ns/jakartaee"
    	xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
    	id="WebApp_ID" version="6.0">
    	<display-name>filterListenerEx</display-name>
    	<welcome-file-list>
    		<welcome-file>index.html</welcome-file>
    		<welcome-file>index.jsp</welcome-file>
    		<welcome-file>index.htm</welcome-file>
    		<welcome-file>default.html</welcome-file>
    		<welcome-file>default.jsp</welcome-file>
    		<welcome-file>default.htm</welcome-file>
    	</welcome-file-list>
    	
    	<filter>
    		<filter-name>IPBlockFliter</filter-name>
    		<filter-class>com.tenco.filters.IPBlockFilter</filter-class>
    	</filter>
    	
    	<filter-mapping>
    		<filter-name>IPBlockFliter</filter-name>
    		<url-pattern>/*</url-pattern>
    	</filter-mapping>
    		
    	<servlet>
    		<description></description>
    		<display-name>HomeServlet</display-name>
    		<servlet-name>HomeServlet</servlet-name>
    		<servlet-class>com.tenco.controller.HomeServlet</servlet-class>
    	</servlet>
    	<servlet-mapping>
    		<servlet-name>HomeServlet</servlet-name>
    		<url-pattern>/HomeServlet</url-pattern>
    	</servlet-mapping>
    </web-app>

    2. 서블릿 리스너

    리스너란?

    컨테이너에서 발생하는 이벤트를 모니터링하다가 특정 이벤트가 발생하면 실행되는 특수한 서블릿으로, '이벤트 리스너'라고도 한다. 즉, 리스너는 웹 애플리케이션에서 특정한 사건이 일어났을 때 그것을 알아차리고 적절한 처리를 하는 역할을 한다. 예를 들어 애플리케이션이 시작되거나 종료될 때 발생하는 사건 이나 사용자가 웹사이트에 로그인하거나 로그아웃하는 등의 사건 또는 사용자가 웹페이지를 요청하거나 특정 작업을 수행할 때 발생하는 사건 등 리스너는 이러한 다양한 사건들을 감지하고, 필요한 작업을 자동으로 수행하는 중요한 역할을 한다.

    WAS 서버에 리스너를 설정하는 방법은 서블릿과 마찬가지로 web.xml 파일에서 설정하거나 자바 코드측에 애노테이션을 사용하여 설정할 수 있는 방법이 존재한다.

     

    예시 코드 - web.xml 파일에 설정 가능

    <web-app ..>
    	<listener>
    	    <listener-class>com.example.AppContextListener</listener-class>
    	</listener>
    </web-app>

     

    예시 코드 - java 파일에 설정 가능

    @WebListener
    public class AppContextListener implements ServletContextListener {
        @Override
        public void contextInitialized(ServletContextEvent sce) {
            // 애플리케이션 시작 시 처리 작업
            System.out.println("Application started at " + new java.util.Date());
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
            // 애플리케이션 종료 시 처리 작업
            System.out.println("Application stopped at " + new java.util.Date());
        }
    }

     

    리스너의 주요 기능

    • 애플리케이션 시작 및 종료 감지
    • 세션 생성 및 소멸 감지
    • 요청 시작 및 종료 감지
    • 애플리케이션 속성 변경 감지

    리스너란?

    리스너는 특정 이벤트가 발생했을 때 이를 감지하고, 그에 대응하는 작업을 수행하는 자바 객체이다. 리스너는 서블릿 컨테이너에서 발생하는 다양한 이벤트를 처리할 수 있다.

     

    사용하는 이유?

    리스너는 웹 애플리케이션의 상태 변화(예: 시작, 종료, 세션 생성 및 소멸)를 감지하여 다음과 같은 작업을 수행할 수 있도록 도와준다.

    • 초기화 작업 (애플리케이션 시작 시 필요한 리소스 로드)
    • 정리 작업 (애플리케이션 종료 시 리소스 해제)
    • 세션 관련 작업 (로그인/로그아웃 로깅, 세션 속성 변경 감지)

    주요 리스너 인터페이스

    • ServletContextListener: 애플리케이션 시작 및 종료 이벤트를 처리한다.
    • HttpSessionListener: 세션 생성 및 소멸 이벤트를 처리한다.
    • ServletRequestListener: 요청 객체의 생성 및 소멸 이벤트를 처리한다.
    AppLifecycleListener
    package com.tenco.listeners;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.logging.Logger;
    
    import jakarta.servlet.ServletContextEvent;
    import jakarta.servlet.ServletContextListener;
    import jakarta.servlet.annotation.WebListener;
    
    /**
     * 리스너 사용해 보기<br>
     * ServletContext 구현 해야 한다.<br>
     * 동작 트리거, web.xml 파일과 어노테이션 기반으로 설정 가능<br>
     * <br>
     */
    @WebListener
    public class AppLifeCycleListener implements ServletContextListener {
    
    	private static final Logger logger = Logger.getLogger(AppLifeCycleListener.class.getName());
    	
    	// 5분
    	private String timeFormat() {
    		// yyyy-MM-dd HH:mm:ss
    		SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    		return formater.format(new Date());
    	}
    	
    	// 애플리케이션이 언제 시작을 했는지 로그, 파일 남겨야 될 때 사용한다라고 가정하자.
    	@Override
    	public void contextInitialized(ServletContextEvent sce) {
    		System.out.println("-----------------------------------");
    		logger.info("웹 애플리케이션 시작됨 >>>> " + timeFormat());
    		System.out.println("-----------------------------------");
    	}
    
    	@Override
    	public void contextDestroyed(ServletContextEvent sce) {
    		System.out.println("-----------------------------------");
    		logger.info("웹 애플리케이션 종료됨 >>>> " + timeFormat());
    		System.out.println("-----------------------------------");
    	}
    }
    MySessionListener
    package com.tenco.listeners;
    
    import java.util.logging.Logger;
    
    import jakarta.servlet.annotation.WebListener;
    import jakarta.servlet.http.HttpSessionEvent;
    import jakarta.servlet.http.HttpSessionListener;
    
    /**
     * 세션이 생성될때 감지... 리스너 등록
     */
    @WebListener
    public class MySessionListener implements HttpSessionListener {
    
    	private static final Logger logger = Logger.getLogger(MySessionListener.class.getName());
    
    	@Override
    	public void sessionCreated(HttpSessionEvent se) {
    		System.out.println("----------------------------------------");
    		// 세션 생성시 실행 됨
    		logger.info("새로운 세션이 생성 됨 : " + se.getSession().getId());
    		se.getSession().setAttribute("loginTime", System.currentTimeMillis());
    	}
    
    	@Override
    	public void sessionDestroyed(HttpSessionEvent se) {
    		// 세션 소멸시 실행 됨
    		Long loginTime = (Long) se.getSession().getAttribute("loginTime");
    		long logoutTime = System.currentTimeMillis();
    		if (loginTime != null) {
    			Long sessionDurationMs = logoutTime - loginTime; // 밀리초 단위
    			double sessionDurationSec = sessionDurationMs / 1000.0; // 초 단위로 변환
    			System.out.println("세션 지속 시간 : " + sessionDurationSec);
    		}
    	}
    }

    JSP 목차로 돌아가기

     

    'Java > JSP' 카테고리의 다른 글

    JSP 라이프사이클  (0) 2024.07.03
    JSP(Java Server Pages)란?  (0) 2024.07.03
    server.xml과 context.xml 그리고 web.xml 파일 이란?  (0) 2024.07.02
    서블릿과 데이터베이스 연동  (0) 2024.07.01
    서블릿과 서블릿 컨텍스트란?  (0) 2024.07.01