As a rising star, JSP can occupy a certain position in the server programming environment, which is closely related to its good support for a series of industry standards. Session is one of the infrastructure it provides. As a programmer, you can easily implement simple session-based user management without worrying about how it is implemented on the client. There are a few different ways to deal with online users these days.
One is that the page refresh is controlled by the user, and the server controls a timeout such as 30 minutes. After the time is up, the user will be kicked out if there is no action. The advantage of this method is that if the user forgets to log out, it can prevent others from malicious operations. The disadvantage is that if you are doing something that takes a lot of time and exceeds this time limit, you may have to log in again when submitting. If the original leaf surface is forced to fail again, you may lose the work you have done. From an implementation perspective, this is the simplest, and the server side implements this mode by default.
Another way is that the site adopts a frame structure, and there is a Frame or hidden iframe that is constantly refreshing, so that you will never be kicked out. However, in order to determine whether you are online, the server needs to set a daze time. If you exceed this daze time, If you do not refresh other pages except this automatically refreshed page, it will be considered that you are no longer online. A typical example of this approach is xici.net. Its advantage is that it can use continuous refresh to implement some server-push-like functions, such as sending messages between netizens.
No matter which mode is used, some additional work needs to be done in order to browse all currently online users. There is no API to get the Session list in the Servlet API.
What can be used is Listener. The Servlet 2.2 and 2.3 specifications are slightly different here. HttpSessionBindingListener in 2.2 can implement a class that notifies you when the Attribute in an HTTPSession changes. HttpSessionAttributeListener was also introduced in 2.3. Since the environment I am using is Visual age for Java 4 and JRun server 3.1, they do not directly support Servlet 2.3 programming. Here I use HttpSessionBindingListener.
Things that need to be done include making a new Class to implement the HttpSessionBindingListener interface. This interface has two methods:
public void valueBound(HttpSessionBindingEvent event)
public void valueUnbound(HttpSessionBindingEvent event)
When you execute Session.addAttribute(String,Object), if you have added a class that implements the HttpSessionBindingListener interface as an Attribute, Session will notify your class and call your valueBound method. On the contrary, the Session.removeAttribute method corresponds to the valueUndound method.
public class HttpSessionBinding implements javax.servlet.http.HttpSessionBindingListener
{
ServletContext application = null;
public HttpSessionBinding(ServletContext application)
{
super();
if (application ==null)
throw new IllegalArgumentException("Null application is not accept.");
this .application = application;
}
public void valueBound(javax.servlet.http.HttpSessionBindingEvent e)
{
Vector activeSessions = (Vector) application.getAttribute("activeSessions");
if (activeSessions == null)
{
activeSessions = new Vector();
}
JDBCUser sessionUser = (JDBCUser)e.getSession().getAttribute("user");
if (sessionUser != null)
{
activeSessions.add(e.getSession());
}
application.setAttribute("activeSessions",activeSessions) ;
}
public void valueUnbound(javax.servlet.http.HttpSessionBindingEvent e)
{
JDBCUser sessionUser = (JDBCUser)e.getSession().getAttribute("user");
if (sessionUser == null)
{
Vector activeSessions = (Vector) application .getAttribute("activeSessions");
if (activeSessions != null)
{
activeSessions.remove(e.getSession().getId());
application.setAttribute("activeSessions",activeSessions);
}
}
}
}
Assume that the JDBCUser Class is an arbitrary User class. When performing user login, add both the User class and the HttpSessionBinding class to the Session.
In this way, every time a user logs in, a record will be added to the attribute "activeSessions" vector in the application. Whenever the session times out, valueUnbound is triggered, and the session that will be timed out is deleted from this vector.
public void login()
throws ACLException,SQLException,IOException
{
/* get JDBC User Class */
if (user != null)
{
logout ();
}
{
// if session time out, or user didn't login, save the target url temporarily.
JDBCUserFactory uf = new JDBCUserFactory();
if ( (this.request.getParameter("userID")==null) || (this.request.getParameter("password")==null) )
{
throw new ACLException("Please input a valid userName and password.");
}
JDBCUser user = (JDBCUser) uf.UserLogin(
this.request. getParameter("userID"),
this.request.getParameter("password") );
user.touchLoginTime();
this.session.setAttribute("user",user);
this.session.setAttribute("BindingNotify",new HttpSessionBinding (application));
}
}
When logging in, add the User and the BindingNotofy purpose class to the session. When logging out, you must actively delete the session in the activeSessions vector.
public void logout()
throws SQLException,ACLException
{
if (this.user == null && this.session.getAttribute("user")==null)
{
return;
}
Vector activeSessions = (Vector) this.application.getAttribute("activeSessions");
if (activeSessions != null)
{
activeSessions.remove(this.session);
application.setAttribute("activeSessions",activeSessions);
}
java.util.Enumeration e = this.session.getAttributeNames();
while (e.hasMoreElements())
{
String s = (String)e.nextElement();
this.session.removeAttribute(s);
}
this.user. touchLogoutTime();
this.user = null;
}
These two functions are located in an HttpSessionManager class. This class refers to the application global object in jsp. The other code of this class has nothing to do with this article and is quite long, so I won’t post it.
Let's take a look at how to use it in JSP.
Assume that a login form is submitted to doLogin.jsp, and the form contains the UserName and password fields. Excerpt:
<%
HttpSessionManager hsm = new HttpSessionManager(application,request,response);
try
{
hsm.login();
}
catch (UserNotFoundException e)
{
response.sendRedirect("InsufficientPrivilege.jsp?detail=User%20does%20not %20exist.");
return;
}
catch (InvalidPasswordException e2)
{
response.sendRedirect("InsufficientPrivilege.jsp?detail=Invalid%20Password");
return;
}
catch (Exception e3)
{
%> Error:<%=e3. toString() %><br>
Press <a href="login.jsp">Here</a> to relogin.
<% return;
}
response.sendRedirect("index.jsp");
%>
Let’s take a look at what we have now How to get a list of currently online users.
<body bgcolor="#FFFFFF">
<table cellspacing="0" cellpadding="0" width="100%">
<tr >
<td style="width:24px">SessionId
</td>
<td style= "width:80px" >User
</td>
<td style="width:80px" >Login Time
</td>
<td style="width:80px" >Last Access Time
</td>
</tr>
<%
Vector activeSessions = (Vector) application.getAttribute("activeSessions");
if (activeSessions == null)
{
activeSessions = new Vector();
application.setAttribute("activeSessions",activeSessions);
}
Iterator it = activeSessions.iterator() ;
while (it.hasNext())
{
HttpSession sess = (HttpSession)it.next();
JDBCUser sessionUser = (JDBCUser)sess.getAttribute("user");
String userId = (sessionUser!=null)?sessionUser.getUserID ():"None";
%>
<tr>
<td nowrap=''><%= sess.getId() %></td>
<td nowrap=''><%= userId %></td>
<td nowrap=''>
<%= BeaconDate.getInstance( new Java.util.Date(sess.getCreationTime())).getDateTimeString()%></td>
<td class="<%= stl %>3 " nowrap=''>
<%= BeaconDate.getInstance( new java.util.Date(sess.getLastAccessedTime())).getDateTimeString()%></td>
</tr>
<%
}
%>
</table>
</body>
The above code retrieves activeSessions from the application and displays the specific time. The BeaconDate class is assumed to be a formatted time class.
In this way, we get a framework for viewing the list of online users. As for online user list paging and other functions, they are irrelevant to this article and will not be discussed.
This is an example of a non-refresh model that relies on the session timeout mechanism. My colleague sonymusic pointed out that many times this may not be reliable due to the different ideas of each manufacturer. Considering this requirement, it is necessary to determine whether the time since the last use by the current user exceeds a predetermined time value when each leaf surface is refreshed. This is essentially implementing session timeout yourself. If you need to implement a refresh model, you must use this method of judging refresh for each leaf surface.