Listener와 Filter

필터와 리스너의 차이

필터는 각각 서블릿에 적용

리스너는 전체 에 적용

 

1.리스너

 

서블릿 컨테이너(톰캣)에서 발생하는 이벤트를 감시하다 특정 이벤트가 발생하면 실행되는 특수한 서블릿

특정 이벤트에 따라  동작하는 인터페이스를 구현한 클래스

리스너는 특정 서블릿이나 JSP가 아닌  웹 어플리케이션 전.체.에. 적.용.하기 위한 필요한 특수한 서블릿이다.

리스너는 생명주기는 생성과 소멸 .(얘는 톰켓인 서블릿컨테이너와 운명을 함께 함)

-리스너가 동작하는 이벤트 종류
  1)Context레벨
.ServletContext 생성과 소멸 관련 이벤트(application)
.ServletContext의 속성  추가set,삭제remove.변경 관련 이벤트
  2)Session수준레벨   
.HttpSession 생성과 소멸 관련 이벤트
.HttpSession의 속성  추가,삭제.변경 관련 이벤트
  3)Request 레벨수준
.HttpRequest 생성과 소멸 관련 이벤트
.HttpRequest의 속성  추가,삭제.변경 관련 이벤트

 

contextInitialized(ServletContextEvent sce) : 서블릿 컨텍스트(웹 어플리에이션)가 시작되면 호출되는 메소드.
                                웹 어플리케이션의 모든 필터 또는 서블릿이 초기화 되기 전에 호출되는 메서드
contextDestroyed(ServletContextEvent sce): 서블릿 컨텍스트가 종료되면 호출되는 메소드 .
                         웹 어플리케이션의 모든 필터 또는 서블릿이 종료된 이후 호출되는 메서드

 

아직까지는 이게 어떤작동을하는지 크게 와 닿지는 않는데 아무튼 톰캣 시작과 끝을 함께하는 서블릿

처음 서버에서 요청이 들어오면 서블릿이 잘 듣고 있다가 요청을 감지하고(listen) 데이터 연결이 필요할 때 앞에서 연경르 해주는 느낌적인 느낌?

작성한 코드를 보면 그런 느낌이 훅 든다.

 

[리스너 구현하기]

MyContextListener

public class MyContextListener implements ServletContextListener {

    public MyContextListener() {
      System.out.println(" MyContextListener()의 생성자");
    }
   //웹 어플리케이션이 시작되면 호출 즉 서블릿 컨텍스트가 생성 될 때
public void contextInitialized(ServletContextEvent sce)  { 
    	
    System.out.println("웹 어플리케이션이 시작 되었습니다.");
    System.out.println("서버정보:+"+sce.getServletContext().getServerInfo());  	

    try {
        Context initCtx = new InitialContext();
        DataSource source = (DataSource)initCtx.lookup(sce.getServletContext().getInitParameter("JNDI-ROOT")+"/jsp");		
        sce.getServletContext().setAttribute("DataSource", source);
    }
    catch(Exception e) {e.printStackTrace();}  	
}

public void contextDestroyed(ServletContextEvent sce)  { 
     System.out.println("웹 어플리케이션이 종료 되었습니다.");
    }
	
}

얘는 어노테이션을 안써서 web.xml에다가 서블릿 등록 해 줘야 함

<listener>
   <listener-class>listener.MyContextListener</listener-class>
</listener>

간편하넴

코드보면 커넥션풀에서 본 코드??

맞음!! 이게 브라우저에서 요청할 때 맨 처음으로 요청을 감지하니까 이때 데이터베이스 연결을 하면  좋겠지

그래서 여기서  커넥션풀에 요청해서 객체 가져옴 

 

그리고 하나 서블릿 더 만드는데 내가 생각한 바로는 setAtrribute 했으니까 잘 set 됐는지 get해서 확인하는 용으로

아직까지는 생각중이다.

MySessionAtrryButeListener

public class MySessionAtrryButeListener implements HttpSessionAttributeListener {

    public MySessionAtrryButeListener() {
       System.out.println("MySessionAtrryButeListener()의 생성자");
    }

    public void attributeReplaced(HttpSessionBindingEvent se)  { 
    	
    	System.out.println("세션속성이 변경"+se.getSession().getId());
    	System.out.println(String.format("변경 된 속성 명:%s, 속성 값:%s",se.getName(),se.getValue()));  
    }

    public void attributeRemoved(HttpSessionBindingEvent se)  { 
    	
    	System.out.println("세션속성이 삭제"+se.getSession().getId());
    	System.out.println(String.format("삭제 된 속성 명:%s, 속성 값:%s",se.getName(),se.getValue()));  
    }


    public void attributeAdded(HttpSessionBindingEvent se)  { 
    	
    	System.out.println("세션속성이 추가"+se.getSession().getId());
    	System.out.println(String.format("추가 된 속성 명:%s, 속성 값:%s",se.getName(),se.getValue())); 
    }
	
}

잘 된건지 확인하려면

저번에 게시판만든거 커넥션풀로 바꿔놨으니 게시판 실행 해 보면 되겠지

 

(필터는 우선 무시하세용 뒤에꺼 해논거라 같이 나온거)

굳굳 잘 나옴


2.필터

개념

서블릿 필터라고도 하며
사용자 요청시 서블릿이 실행되기전에 사용자 요청을 가로채서 특정 작업(사전처리 혹은 사후처리)을 할 수 있도록
 해주는 특수한 형태의 서블릿이다. 엉? 리스너랑 비슷 한건가?

필터는 컨테이너에 등록한 설정대로 특.정. 요.청.에.만. 동작하며 하나 혹은 여러개의 필터가  사용자의 요청처리 이전에 먼저 실행된다(전체에 적용하는 리스너랑은 조금 다름)

필터는 기존 코드의 변경없이 웹 어플리케이션에서 공통적으로 사용할 수 있는기능 구현에 사용된다

여러 개 필터를 사용하는 경우 필터 하나당 하나의 기능을 갖도록 정의

필터는 서블릿 컨테이너가 시작될 때 생성된다(Pre-Loading:사용자 요청이 없어도 사전에 생성됨)
 단,서블릿은 사용자 요청이 있을 때 생성된다(Lazy Loadong:사용자 요청이 있을 때 생성됨)

 

인증/로그인/한글인코딩 처리등 할 때 필터를 이용한다!

필터 생명주기에 관한 메소드

init() : 서블릿 컨테이너(톰캣)에 필터가 등록되어  초기화 될 때 실행된다.한 번만 실행됨
doFilter(): 필터가 매핑된 서블릿에 사용자 요청이 들어왔을 때 요청이 전달되기 전에 실행된다.
                    서블릿으로 사용자 요청이 들어올때마다 실행됨.
                    인자인 FilterChain의 doFilter()를 호출해야 다음 필터로 요청이 전달되고 
최종적으로 서블릿에게 전달된다
만약 doFilter()를 호출하지 않는다면 해당 필터가 가로챈 요청이 서블릿에게 전달되지 않는다
destroy():서블릿 컨테이너가 종료되기전 필터가 종료될 때 실행된다. 한 번만 실행됨

 

필터 구현하기

이번에도 어노테이말고 그냥 서블릿 등록함 여기까지만 하고 이젠 어노테이션 쓸거임

그리고 필터의 

chain.doFilter의 기능도 잘 알아놔야함 !!

chain 이란걸 쓸거라서 인자도 하나 더늘어남 잘 봐두세요

/*web.xml에서 등록했으면 여기선 어노테이션으로 또 처리하면 안됨
만약 여기서 처리한다면
@WebFilter(urlPatterns = {"/bbs08/*","*.kosmo"}) 
두 폴더에 같은 필터를 적용할 때 저렇게 묶어주면 된다 !!*/
public class RuntimeFilter extends HttpFilter implements Filter {       
 
    public RuntimeFilter() {
        System.out.println("RuntimeFilter생성자");
    }

	public void destroy() {
		System.out.println("RuntimeFilter destroy()호출");
	}
	
	 //서블릿의 doGet()/doPost()가 호출되기전에 호출된다
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		
		// 필터가 서블릿으로 가지 전에 필터가 먼저 가로채서 사전작업 코드를 실행(?)		
		System.out.println("=====doFilter호출 전 사전 작업=======");
		HttpServletRequest req =(HttpServletRequest)request;
		String uri=req.getRequestURI();
		long startTime= System.currentTimeMillis();
		chain.doFilter(request, response);   //다음 필터 혹은 서블릿으로 요청 전달
		
		//다시 와서 사후 작업 코드 
		System.out.println("=====doFilter호출 후 사후 작업=======");
		long endTime= System.currentTimeMillis();
		System.out.println(String.format("요청URI:%s,서블릿 실행 시간:%s",uri,(endTime-startTime)/1000.0+"초"));
	}

	public void init(FilterConfig fConfig) throws ServletException {
		System.out.println("RuntimeFilter init()호출");
	}

}

진짜 작업 할 필터를 만들어서 적용시켜 보자

우리가 만든게시판에 로그인여부를 판단하는 필터를 껴보겠음

++필터에다가 로그인여부 판단하는걸 넣어놓으면

페이지 일일이 다 코드를 넣을 필요가 없어짐

그용도로 필터를 쓴다...

아...

//bbs08파일에 모든 파일에 필터를 적용하는 것은 *로 해주고 경로에 컨텍스트루트 제외한다.
@WebFilter("/bbs08/*")
public class AuthenticationFilter extends HttpFilter implements Filter {
	 
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		//필터에서 로그인여부 판단
		HttpServletRequest req =(HttpServletRequest)request;
		Object checkLogin = req.getSession().getAttribute("USER-ID");
		if(checkLogin == null ) {  
		/* 이제 이렇게 안쓰고 
			HttpServletResponse resp = (HttpServletResponse)response;
			resp.setContentType("text/html; charset=UTF-8");
			PrintWriter out=resp.getWriter();
			out.println("<script>");
			out.println("alert('로그인 후 이용하세요!');");
			out.println("location.replace('"+req.getContextPath()+"/session06/Login.jsp');");
			out.println("</script>");
			*/
            
			req.setAttribute("NOT-LOGIN","로그인 후 이용하세요");
			req.getRequestDispatcher("/session06/Login.jsp").forward(request, response);
			return;
		}
		chain.doFilter(request, response);
	}

}

신기해신기해...

 

필터 만들 떄 도구 사용 가능하고

 

 

필터 적용 했는데 로그인이 안되서 왜그러지 했는데

아...

필터 적용 후 bbs모든 ismember태그 주석처리하고

bbs의 경로 랑

login 페이지에 로그인 경로는 상대경로에서 절대경로로 바꿔야함

<%=request.getContextPath() %>/session06/LoginProcess.jsp     !!!

경고창 추가하기 !!!

 

 

+ Recent posts