웹 개발 기초/자바 웹을 다루는 기술

HttpSessionListener 이용해 로그인 접속자 수 표시

sungw00 2023. 2. 23. 02:27
728x90

setAttribute( )를 이용해 loginUser를 세션에 바인딩하면 LoginImpl 클래스에 구현된 이벤트 핸들러를 이용해 접속자수를 1 증가시키고, user_list에 접속자 ID를 저장한 다음 ServletContext 객체에 바인딩한다.

// LoginTest3.java
package sec04.ex02;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Servlet implementation class LoginTest2
 */
@WebServlet("/login")
public class LoginTest3 extends HttpServlet {
	ServletContext context=null;
	List user_list=new ArrayList(); // 로그인한 접속자 ID를 저장하는 ArrayList
	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=utf-8");
		context=getServletContext();
		PrintWriter out = response.getWriter();
		HttpSession session = request.getSession();
		String user_id = request.getParameter("user_id");
		String user_pw = request.getParameter("user_pw");
		LoginImpl loginUser = new LoginImpl(user_id, user_pw); // LoginImpl 객체 생성 후 전송된 ID와 비밀번호 저장
		// 최초 로그인 시 접속자 ID를 ArrayList에 차례로 저장한 후 다시 context 객체에 속성으로 저장
        if(session.isNew()) {
			session.setAttribute("loginUser", loginUser);
			user_list.add(user_id);
			context.setAttribute("user_list", user_list);
		}
		
		out.println("<html><body>");
		out.println("아이디는 " + loginUser.user_id + "<br>");
		out.println("총 접속자수는 " + LoginImpl.total_user + "<br><br>"); // 세션에 바인딩 이벤트 처리 후 총 접속자수를 표시
		out.println("접속 아이디:<br>");
		List list=(ArrayList)context.getAttribute("user_list"); // context 객체에 ArrayList를 가져와 접속자 ID를 차례로 브라우저에 출력
		for(int i=0; i<list.size(); i++) {
			out.println(list.get(i)+"<br>");
		}
		out.println("<a href='logout?user_id="+user_id+"'>로그아웃 </a>"); // 로그아웃 클릭 시 서블릿 logout으로 접속자 ID를 전송해 로그아웃
		out.println("</body></html>");
	}

}
// LoginImpl.java
package sec04.ex01;

import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

public class LoginImpl implements HttpSessionBindingListener {
	String user_id;
	String user_pw;
	static int total_user=0;
	public LoginImpl() {
	}
	
	public LoginImpl(String user_id, String user_pw) {
		this.user_id = user_id;
		this.user_pw = user_pw;
	}
	
	public void valueBound(HttpSessionBindingEvent arg0) {
		System.out.println("사용자 접속");
		++total_user;
	}
	
	public void valueUnbound(HttpSessionBindingEvent arg0) {
		System.out.println("사용자 접속 해제");
		total_user--;
	}
}

 

로그아웃 링크를 클릭하면 접속자 수를 1 감소시키고 user_list에서 로그아웃한 접속자 ID를 삭제한 후 다시 user_list를 ServletContext 객체에 바인딩하도록 설정한다.

// LogoutTest.java
package sec04.ex02;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Servlet implementation class LogoutTest
 */
@WebServlet("/logout")
public class LogoutTest extends HttpServlet {
	ServletContext context;
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doHandle(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doHandle(request, response);
	}
	
	private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=utf-8");
		context=getServletContext();
		PrintWriter out = response.getWriter();
		HttpSession session = request.getSession();
		String user_id = request.getParameter("user_id"); // user_list에서 삭제할 ID를 가져옴
		session.invalidate(); // 로그아웃 시 세션을 소멸 시킴
        	// user_list에서 로그아웃한 접속자 ID를 삭제한 후 다시 user_list를 컨텍스트에 저장함
		List user_list = (ArrayList)context.getAttribute("user_id");
		user_list.remove(user_id);
		context.removeAttribute("user_list");
		context.setAttribute("user_list", user_list);
		out.println("<br>로그아웃 했습니다.");
	}

}

 

LoginImpl 클래스는 HttpSessionListener를 구현해 세션 생성과 소멸 시 이벤트를 처리하는 핸들러이다.

중요한 것은 앞의 LoginImpl에서 구현한 HttpSessionBindingListener와는 다르게 HttpSessionListener는 반드시 리스너를 구현한 이벤트 핸들러를 애너테이션을 이용해서 등록해야 한다는 것이다. 아래는 직접 구현하는 방법이다.


패키지 우클릭 -> New -> Listener 클릭

 

Class name으로 LoginImpl 입력 후 Next 클릭

HTTP session events의 Lifecycle javax.servlet.http.HttpSessionListener 체크 후 Next 클릭

Finish 클릭

@WebListener 애너테이션으로 리스너가 등록된 것을 확인

 

리스너를 등록한 이벤트 핸들러를 이용해 세션을 생성할 때는 sessionCreated( ) 메서드로 이벤트를 처리하고, 세션을 삭제할 때는 sessionDestroyed( ) 메서드로 이벤트를 처리한다.

package sec04.ex02;

import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

@WebListener // HttpSessionBindingListener를 제외한 Listener를 구현한 모든 이벤트 핸들러는 반드시 애너테이션을 이용해 Listener로 등록해야 함
public class LoginImpl implements HttpSessionListener {
	String user_id;
	String user_pw;
	static int total_user=0;

    public LoginImpl() {
    }

    @Override
    // 세션 생성 시 이벤트를 처리함
    public void sessionCreated(HttpSessionEvent se)  { 
    	System.out.println("세션 생성");
    	++total_user;
    }

    @Override
    // 세션 소멸 시 이벤트를 처리함
    public void sessionDestroyed(HttpSessionEvent se)  { 
    	System.out.println("세션 소멸");
    	--total_user;
    }
	
}

 

실행하면 사용자마다 로그인/로그아웃 시 접속자수와 접속자 ID를 표시한다. 

먼저 첫 번째 아이디로 로그인한 결과이다.

크롬에서 로그인 시 결과

두 번째 아이디 hong으로 로그인 한 결과이다.

익스플로러에서 로그인 시 결과

 

그리고 hong 아이디로 로그인 한 익스플로러 창에서 로그아웃을 클릭하고, 크롬에서 재요청 하면 다음과 같이 접속자 수가 2에서 1로 감소한다.

익스플로러 로그아웃 후 결과

다른 리스너에서도 세부 기능을 익히고 나면 고급 기능도 쉽게 구현이 가능하다.

728x90