[Java] Session을 이용한 동시 접속자 수(로그인 수) 카운트하기

최용혁·2025년 2월 4일

🚀 싱글톤 패턴을 사용해 단 하나의 LoginManager객체로 웹에서 로그인한 사용자의 세션을 관리한다.

1. singleton 패턴 구현

private static LoginManager loginManager = null;

public static synchronized LoginManager getInstance() {
    if (loginManager == null) {
        loginManager = new LoginManager();
    }
    return loginManager;
}
  • LoginManager가 한번만 생성되도록 하는 싱글톤패턴 구현 .
  • synchronized 키워드로 멀티스레드 환경에서의 동시성 문제 방지.

✅세션이벤트 감지 (로그인 & 로그아웃)

2. 로그인 시

public void valueBound(HttpSessionBindingEvent event) {
    System.out.println("valueBound 호출됨: " + event.getSession().getId());
    loginUsers.put(event.getSession(), event.getName());
    userCount++;
    System.out.println("현재 접속자 수: " + getUserCount());
}
  • 세션에 객체가 추가될 때 (session.setAttribute()) 자동 실행됨
  • 로그인한 사용자를 loginUsers 해시테이블에 저장.
  • userCount++ 증가.

3. 로그아웃 시

public void removeSession(String userId) {
    Enumeration e = loginUsers.keys();
    HttpSession session = null;
    while (e.hasMoreElements()) {
        session = (HttpSession) e.nextElement();
        if (loginUsers.get(session).equals(userId)) {
            session.invalidate(); // 세션 제거 (valueUnbound() 호출됨)
        }
    }
}
  • 특정 사용자(userId)가 로그인 중인지 확인하고, 로그아웃 처리.
  • session.invalidate();를 호출하면 valueUnbound()가 실행됨 → 자동 로그아웃.
public void valueUnbound(HttpSessionBindingEvent event) {
    loginUsers.remove(event.getSession());
    userCount--;
}
  • 세션이 만료되거나 삭제될 때 (session.invalidate()) 자동 실행
  • 사용자를 loginUsers에서 제거.
  • userCount-- 감소.

4. 로그인 완료 후 세션에 사용자 정보 저장 (setSession())

public void setSession(HttpSession session, String userId) {
    session.setAttribute(userId, this);
}
  • 세션에 사용자 ID와 LoginManager 객체를 저장.
  • session.setAttribute()를 호출하면 valueBound()가 실행됨 → 자동으로 로그인 처리.

5. 현재 접속자 수 조회 (getUserCount())

public int getUserCount() {
    return loginUsers.size();
}
  • 현재 로그인한 사용자 수 반환.

흐름

1️⃣ 로그인(loginaction.jsp)

<%@page import="dao.UserDAO"%>
<%@page import="java.io.PrintWriter"%>
<%@page import="vo.User"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<%
	String id = request.getParameter("userId");
	String pw = request.getParameter("userPw");
	// 세션이 있으면 유저 변수에 세션 값 저장
	User user = (User) session.getAttribute("userId");

	PrintWriter out1 = response.getWriter();
	String result = null;

	// 세션이 없으면(로그인이 안되어있는 상황) user에 id, pw기준으로 검색후 해당 유저 변수저장 없으면 null
	try{
		if (user == null) {
			user = UserDAO.getUser(id, pw);
			if(user == null){
				result = "0";
			}else{
				// 세션에 회원 id를 id로 하여 player를 객체로 추가
				session.setAttribute("userId", user);
				result = "1";
			}
		}
	}catch(Exception e){
		result = "9";
	}
	

	System.out.println(session.getAttribute("userId"));
	out1.println(result);
	out1.close();
	%>
</body>
</html>
  • session.setAttribute("userId", user);부분에서 valueBound함수가 실행되어 유저를 세션에 저장시키고, userCount증가.

2️⃣ 동시접속자 수(로그인한사용자 수 ) 보여주기(header.jsp)

 <%
        User user = (User) session.getAttribute("userId");
        LoginManager loginManager = LoginManager.getInstance();
        
        // 사용자 정보를 바탕으로 세션에 로그인 상태 저장
        if (user != null) {
            loginManager.setSession(session, user.userId);
        }
        
        int userCount = loginManager.getUserCount(); // 사용자 수 가져오기
    %>
    <p id="user_font">
    		<span class="user-wrapper">
        	<img src="../image/numicon2.png" class="user" alt="Online Icon">
        	<span class="user-count"><%= userCount %></span>
        	<img src="../image/numicon.png" class="user" alt="Person Icon">
    	</span>
    	</p>
  • userCount를 통해 현재 로그인 한 사용자 수 시각화.

3️⃣ 로그아웃(logoutaction.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<%
		// 세션이 가진 모든 attribute를 리셋
		session.invalidate();
	%>
	<jsp:forward page="../login/nexonLogin.jsp"></jsp:forward>
</body>
</html>
  • session.invalidate();가 실행되어 LoginManager의 removeSession이 실행.

🎯실행흐름 요약

  1. 사용자가 로그인하면 setSession(session, userId)이 실행됨.
  2. session.setAttribute()가 호출되면서 valueBound()가 실행됨.
  3. loginUsers 해시테이블에 세션과 userId가 저장됨.
  4. 사용자가 로그아웃하면 removeSession(userId)가 실행됨.
  5. session.invalidate()로 인해 valueUnbound()가 실행됨.
  6. loginUsers에서 해당 사용자가 제거됨.

로그인

동시접속자 수

로그아웃

동시접속자 수

🚀 추가 고려사항

  • session 타임아웃 처리
session.setMaxInactiveInterval(30 * 60);  // 30분
profile
안녕하세용

0개의 댓글