๋ฆฌ์ค๋๋ ์ด๋ฒคํธ๋ฅผ ๊ฐ์งํ๊ณ ์ฒ๋ฆฌํ๋ ๊ฐ์์ ์ญํ ์ ํ๋ฉฐ, ์น ์ ํ๋ฆฌ์ผ์ด์
์ ์๋ช
์ฃผ๊ธฐ๋ ์ํ ๋ณํ์ ์๋์ผ๋ก ๋ฐ์ํ ์ ์๋๋ก ํด์ค๋๋ค.
Listener๋?
์น ์ ํ๋ฆฌ์ผ์ด์
๋ด์์ ๋ฐ์ํ๋ ํน์ ์ด๋ฒคํธ ์ ๋ํด ์๋์ผ๋ก ์คํ๋๋ ์ฝ๋๋ฅผ ํฌํจํ๋ ํด๋์ค์
๋๋ค.
โข
์ด๋ฒคํธ (์: ์ธ์
์์ฑ, ์ ํ๋ฆฌ์ผ์ด์
์์ ๋ฑ)
๋ฆฌ์ค๋๋ ์๋ธ๋ฆฟ ์ปจํ
์ด๋(Tomcat ๋ฑ)๊ฐ ์๋์ผ๋ก ํธ์ถํฉ๋๋ค. ์ฆ, ๊ฐ๋ฐ์๊ฐ ์ง์ ํธ์ถํ์ง ์์๋ ๋ฉ๋๋ค.
์ฃผ์ Listener ์ข
๋ฅ
Listener ์ธํฐํ์ด์ค | ๊ฐ์ง ๋์ (์ด๋ฒคํธ) | ์ฃผ ์ฌ์ฉ ๋ชฉ์ |
ServletContextListener | ์น ์ ํ๋ฆฌ์ผ์ด์
์์/์ข
๋ฃ | ์ด๊ธฐ ์ค์ , ๋ฆฌ์์ค ์ ๋ฆฌ ๋ฑ |
HttpSessionListener | ์ธ์
์์ฑ/์ข
๋ฃ | ๋ก๊ทธ์ธ ์ถ์ , ์ธ์
์ ๊ด๋ฆฌ |
ServletRequestListener | ์์ฒญ ์์/์ข
๋ฃ | ์์ฒญ ์๊ฐ ์ธก์ , ๋ก๊น
๋ฑ |
HttpSessionAttributeListener | ์ธ์
์์ฑ ๋ณ๊ฒฝ | ๋ก๊ทธ์ธ ์ ๋ณด ์ถ์ ๋ฑ |
ServletContextAttributeListener | ์ปจํ
์คํธ ์์ฑ ๋ณ๊ฒฝ | ์ ์ญ ์ค์ ๋ณ๊ฒฝ ๊ฐ์ |
ServletRequestAttributeListener | ์์ฒญ ์์ฑ ๋ณ๊ฒฝ | ๋๋ฒ๊น
, ๋ก๊น
๋ฑ |
1. ServletContextListener
์ญํ :
โข
์น ์ฑ ์์/์ข
๋ฃ ์์ ์ ๋์
์ฝ๋ ์์:
@WebListener
public class AppStartListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
System.out.println("๐ ์น ์ ํ๋ฆฌ์ผ์ด์
์์๋จ");
}
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("๐ ์น ์ ํ๋ฆฌ์ผ์ด์
์ข
๋ฃ๋จ");
}
}
Java
๋ณต์ฌ
2. HttpSessionListener
์ญํ :
โข
์ธ์
์์ฑ/์ข
๋ฃ ๊ฐ์ง (๋ก๊ทธ์ธ ์ํ ๋ฑ ์ถ์ )
์ฝ๋ ์์:
@WebListener
public class SessionTracker implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent se) {
System.out.println("๐ข ์ธ์
์์ฑ๋จ: " + se.getSession().getId());
}
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("๐ด ์ธ์
์ข
๋ฃ๋จ: " + se.getSession().getId());
}
}
Java
๋ณต์ฌ
3. ServletRequestListener
์ญํ :
โข
HTTP ์์ฒญ์ ์์/์ข
๋ฃ ๊ฐ์ง
์ฝ๋ ์์:
@WebListener
public class RequestLogger implements ServletRequestListener {
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("โก๏ธ ์์ฒญ ์์๋จ: " + ((HttpServletRequest) sre.getServletRequest()).getRequestURI());
}
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("โฌ
๏ธ ์์ฒญ ์ข
๋ฃ๋จ");
}
}
Java
๋ณต์ฌ
๋ฆฌ์ค๋ ๋ฑ๋ก ๋ฐฉ๋ฒ
1.
์ด๋
ธํ
์ด์
์ฌ์ฉ (@WebListener) โ ์ต์ ๋ฐฉ์
2.
web.xml์ ๋ฑ๋ก โ ์ ํต ๋ฐฉ์
<!-- web.xml ๋ฐฉ์ ์์ -->
<listener>
<listener-class>com.example.MyListener</listener-class>
</listener>
XML
๋ณต์ฌ
์ฌ์ฉ ์
์๋๋ฆฌ์ค | ํ์ฉํ ๋ฆฌ์ค๋ |
์น ์ฑ ์์ ์ DB ์ฐ๊ฒฐ ํ ์์ฑ | ServletContextListener |
์ฌ์ฉ์ ๋ก๊ทธ์ธ ์ ์นด์ดํ
| HttpSessionListener |
์์ฒญ ๋ก๊ทธ ๊ธฐ๋ก | ServletRequestListener |
๋ก๊ทธ์ธ ์ฌ์ฉ์ ์ ๋ณด ์ถ์ | HttpSessionAttributeListener |
์ ์ญ ์ค์ ๋ณ๊ฒฝ ๊ฐ์ | ServletContextAttributeListener |
์ ๋ฆฌ
๋ฆฌ์ค๋ ์ข
๋ฅ | ๊ฐ์ง ์์ |
ServletContextListener | ์น ์ฑ ์์/์ข
๋ฃ |
HttpSessionListener | ์ธ์
์์ฑ/์ข
๋ฃ |
ServletRequestListener | ์์ฒญ ์์/์ข
๋ฃ |
์์ฑ ๊ด๋ จ ๋ฆฌ์ค๋๋ค | ์์ฑ ์ถ๊ฐ/๋ณ๊ฒฝ/์ญ์ ์์ |
์ค์๊ฐ ์ ์์ ์
์ธ์
๋ฆฌ์ค๋๋ก ์ค์๊ฐ ์ ์์ ์ ๊ตฌํ
์ธ์
์ด ์์ฑ๋๊ณ ์ข
๋ฃ๋ ๋๋ง๋ค ์ ์์ ์๋ฅผ ์นด์ดํ
ํ์ฌ ์ค์๊ฐ์ผ๋ก ์ถ์ ํ ์ ์์ต๋๋ค.
SessionCountListener ๊ตฌํ
@WebListener
public class SessionCountListener implements HttpSessionListener {
private static int activeSessions = 0;
public void sessionCreated(HttpSessionEvent se) {
activeSessions++;
ServletContext context = se.getSession().getServletContext();
context.setAttribute("activeSessions", activeSessions);
System.out.println("๐ข ์ธ์
์์ฑ | ํ์ฌ ์ ์์ ์: " + activeSessions);
}
public void sessionDestroyed(HttpSessionEvent se) {
activeSessions--;
ServletContext context = se.getSession().getServletContext();
context.setAttribute("activeSessions", activeSessions);
System.out.println("๐ด ์ธ์
์ข
๋ฃ | ํ์ฌ ์ ์์ ์: " + activeSessions);
}
public static int getActiveSessions() {
return activeSessions;
}
}
Java
๋ณต์ฌ
Servlet์์ ์ ์์ ์ ์กฐํ
@WebServlet("/visitor-count")
public class VisitorCountServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// ServletContext์์ ์ ์์ ์ ๊ฐ์ ธ์ค๊ธฐ
int count = (int) getServletContext().getAttribute("activeSessions");
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<h1>ํ์ฌ ์ ์์ ์: " + count + "๋ช
</h1>");
}
}
Java
๋ณต์ฌ
JSP์์ ์ ์์ ์ ํ์
<%@ page language="java" contentType="text/html; charset=UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<title>์ค์๊ฐ ์ ์์</title>
</head>
<body>
<h2>๐ ํ์ฌ ์ ์์ ์</h2>
<p>์ ์ ์ค์ธ ์ฌ์ฉ์: <strong>${applicationScope.activeSessions}</strong>๋ช
</p>
</body>
</html>
XML
๋ณต์ฌ
๋์ ์๋ฆฌ
โข
์ธ์
์์ฑ ์: sessionCreated()๊ฐ ํธ์ถ๋์ด activeSessions ์ฆ๊ฐ
โข
์ธ์
์ข
๋ฃ ์: sessionDestroyed()๊ฐ ํธ์ถ๋์ด activeSessions ๊ฐ์
โข
ServletContext์ ์ ์ฅ: ์ ์ญ ๋ฒ์์์ ์ ์์ ์ ๊ณต์
โข
JSP/Servlet์์ ์กฐํ: ${applicationScope.activeSessions} ๋๋ getAttribute()๋ก ์ ๊ทผ
๋์ ์ ์ ์ ํ
๋์ ์ ์ ์ ํ ๊ตฌํ (์ต๋ 3๊ฐ ์ธ์
)
๋์ผํ ์ฌ์ฉ์ ID๊ฐ 3๊ฐ ์ด์์ ์ธ์
์ผ๋ก ์ ์ํ๋ ๊ฒ์ ๋ฐฉ์งํ๋ ๊ธฐ๋ฅ์
๋๋ค.
SessionLimitListener ๊ตฌํ
@WebListener
public class SessionLimitListener implements HttpSessionListener, HttpSessionAttributeListener {
// ์ฌ์ฉ์๋ณ ์ธ์
๋ชฉ๋ก ์ ์ฅ (userId โ List<HttpSession>)
private static Map<String, List<HttpSession>> userSessions = new ConcurrentHashMap<>();
private static final int MAX_SESSIONS = 3;
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("๐ข ์ธ์
์์ฑ: " + se.getSession().getId());
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession();
String userId = (String) session.getAttribute("userId");
if (userId != null) {
List<HttpSession> sessions = userSessions.get(userId);
if (sessions != null) {
sessions.remove(session);
if (sessions.isEmpty()) {
userSessions.remove(userId);
}
System.out.println("๐ด ์ธ์
์ข
๋ฃ: " + userId + " | ๋จ์ ์ธ์
: " + sessions.size());
}
}
}
@Override
public void attributeAdded(HttpSessionBindingEvent event) {
if ("userId".equals(event.getName())) {
String userId = (String) event.getValue();
HttpSession newSession = event.getSession();
// ํด๋น ์ฌ์ฉ์์ ์ธ์
๋ชฉ๋ก ๊ฐ์ ธ์ค๊ธฐ
List<HttpSession> sessions = userSessions.computeIfAbsent(userId, k -> new ArrayList<>());
// ์ด๋ฏธ 3๊ฐ ์ด์์ด๋ฉด ๊ฐ์ฅ ์ค๋๋ ์ธ์
๊ฐ์ ์ข
๋ฃ
if (sessions.size() >= MAX_SESSIONS) {
HttpSession oldestSession = sessions.get(0);
oldestSession.invalidate();
System.out.println("โ ๏ธ ์ต๋ ์ ์ ์ด๊ณผ | ๊ฐ์ฅ ์ค๋๋ ์ธ์
์ข
๋ฃ: " + oldestSession.getId());
}
// ์ ์ธ์
์ถ๊ฐ
sessions.add(newSession);
System.out.println("โ
์ฌ์ฉ์ '" + userId + "' ๋ก๊ทธ์ธ | ํ์ฌ ์ธ์
์: " + sessions.size());
}
}
@Override
public void attributeRemoved(HttpSessionBindingEvent event) {
// ๋ก๊ทธ์์ ์ ์ฒ๋ฆฌ
}
@Override
public void attributeReplaced(HttpSessionBindingEvent event) {
// ์์ฑ ๋ณ๊ฒฝ ์ ์ฒ๋ฆฌ
}
}
Java
๋ณต์ฌ
๋ก๊ทธ์ธ Servlet์์ userId ์ค์
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String userId = request.getParameter("userId");
String password = request.getParameter("password");
// ๋ก๊ทธ์ธ ๊ฒ์ฆ (๊ฐ๋จ ์์)
if (userId != null && !userId.isEmpty()) {
// ์ธ์
์ userId ์ ์ฅ โ ๋ฆฌ์ค๋๊ฐ ์๋์ผ๋ก ๊ฐ์ง
request.getSession().setAttribute("userId", userId);
response.sendRedirect("main.jsp");
} else {
response.sendRedirect("login.jsp?error=1");
}
}
}
Java
๋ณต์ฌ
๋ก๊ทธ์ธ ํ์ด์ง (login.jsp)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>๋ก๊ทธ์ธ</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0;
}
.login-container {
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
width: 300px;
}
h2 {
text-align: center;
color: #333;
}
input[type="text"], input[type="password"] {
width: 100%;
padding: 10px;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
button {
width: 100%;
padding: 10px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background-color: #45a049;
}
.error {
color: red;
text-align: center;
margin-top: 10px;
}
</style>
</head>
<body>
<div class="login-container">
<h2>๐ ๋ก๊ทธ์ธ</h2>
<form action="login" method="post">
<input type="text" name="userId" placeholder="์์ด๋" required>
<input type="password" name="password" placeholder="๋น๋ฐ๋ฒํธ" required>
<button type="submit">๋ก๊ทธ์ธ</button>
</form>
<% if (request.getParameter("error") != null) { %>
<p class="error">โ ๏ธ ๋ก๊ทธ์ธ ์ ๋ณด๋ฅผ ํ์ธํด์ฃผ์ธ์.</p>
<% } %>
<% if (request.getParameter("limit") != null) { %>
<p class="error">โ ๏ธ ์ต๋ ์ ์ ์๋ฅผ ์ด๊ณผํ์ฌ ๊ฐ์ฅ ์ค๋๋ ์ธ์
์ด ์ข
๋ฃ๋์์ต๋๋ค.</p>
<% } %>
</div>
</body>
</html>
XML
๋ณต์ฌ
IP ๊ธฐ๋ฐ ์ ํ (์ ํ ์ฌํญ)
PC๋ IP ๊ธฐ๋ฐ์ผ๋ก ์ ํํ๋ ค๋ฉด userId ๋์ IP ์ฃผ์๋ฅผ ํค๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
@Override
public void sessionCreated(HttpSessionEvent se) {
HttpSession session = se.getSession();
// IP ์ฃผ์ ๊ฐ์ ธ์ค๊ธฐ
ServletRequest request = ...; // ์ค์ ๋ก๋ Filter์์ ์ฒ๋ฆฌ ํ์
String ipAddress = request.getRemoteAddr();
session.setAttribute("ipAddress", ipAddress);
}
Java
๋ณต์ฌ
๋์ ํ๋ฆ
1.
๋ก๊ทธ์ธ ์: userId๊ฐ ์ธ์
์ ์ ์ฅ๋จ โ attributeAdded() ํธ์ถ
2.
์ธ์
์ ํ์ธ: ํด๋น ์ฌ์ฉ์์ ์ธ์
์ด 3๊ฐ ์ด์์ด๋ฉด ๊ฐ์ฅ ์ค๋๋ ์ธ์
๊ฐ์ ์ข
๋ฃ
3.
์ ์ธ์
์ถ๊ฐ: ํ์ฌ ์ธ์
์ ์ฌ์ฉ์๋ณ ์ธ์
๋ชฉ๋ก์ ์ถ๊ฐ
4.
๋ก๊ทธ์์/์ธ์
๋ง๋ฃ: sessionDestroyed()์์ ๋ชฉ๋ก์์ ์ ๊ฑฐ
์ฃผ์์ฌํญ
โข
ConcurrentHashMap ์ฌ์ฉ: ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์ ์์ ํ๊ฒ ๊ด๋ฆฌ
โข
๊ฐ์ฅ ์ค๋๋ ์ธ์
์ข
๋ฃ: sessions.get(0)์ด ๊ฐ์ฅ ๋จผ์ ์ถ๊ฐ๋ ์ธ์
โข
IP ๊ธฐ๋ฐ ์ ํ ์: ๋์ IP ํ๊ฒฝ์์๋ ์ ํ์ด ์ด๋ ค์ธ ์ ์์
โข
PC ์๋ณ: ์์ ํ PC ์๋ณ์ ์ด๋ ค์ฐ๋ฏ๋ก IP + User-Agent ์กฐํฉ ์ฌ์ฉ ๊ถ์ฅ


