需求:
1.管理员后台可显示当前在线访客数以及在线会员数(在线会员要求列出详细清单).
2.某个客户端非法退出(直接关闭浏览器或断电啥的)后,接着他重新登录系统.在线统计上要做到保持登录统计的准确性与完整性.
3.防止多个客户端同时使用一个帐户异地登录(后登录者踢掉先登录者,并通知先登录者被迫下线).
1.监听器SessionListener (web.xml的代码略)
- /**
- * 创建session
- */
- public void sessionCreated(HttpSessionEvent se) {
- OnlineStatistics.increase();
- }
- /**
- * 服务器销毁session对象
- */
- public void sessionDestroyed(HttpSessionEvent se) {
- OnlineStatistics.decrease();
- }
- /**
- * 用户登录时
- */
- public void attributeAdded(HttpSessionBindingEvent se) {
- if ("memberInfo".equals(se.getName())) {
- MemberInfo memberInfo = (MemberInfo) se.getValue();
- OnlineStatistics.addAttr(memberInfo);
- se.getSession().setMaxInactiveInterval(60 * 20);// 失效时间SEC * MINS
- }
- }
- /**
- * 用户退出登录(销毁session属性时)
- */
- public void attributeRemoved(HttpSessionBindingEvent se) {
- if ("memberInfo".equals(se.getName())) {
- MemberInfo memberInfo = (MemberInfo) se.getValue();
- OnlineStatistics.removeAttr(memberInfo);
- memberInfo = null;
- }
- }
- /**
- * 待实现
- */
- public void attributeReplaced(HttpSessionBindingEvent se) {
- //to be extended
- }
/**
* 创建session
*/
public void sessionCreated(HttpSessionEvent se) {
OnlineStatistics.increase();
}
/**
* 服务器销毁session对象
*/
public void sessionDestroyed(HttpSessionEvent se) {
OnlineStatistics.decrease();
}
/**
* 用户登录时
*/
public void attributeAdded(HttpSessionBindingEvent se) {
if ("memberInfo".equals(se.getName())) {
MemberInfo memberInfo = (MemberInfo) se.getValue();
OnlineStatistics.addAttr(memberInfo);
se.getSession().setMaxInactiveInterval(60 * 20);// 失效时间SEC * MINS
}
}
/**
* 用户退出登录(销毁session属性时)
*/
public void attributeRemoved(HttpSessionBindingEvent se) {
if ("memberInfo".equals(se.getName())) {
MemberInfo memberInfo = (MemberInfo) se.getValue();
OnlineStatistics.removeAttr(memberInfo);
memberInfo = null;
}
}
/**
* 待实现
*/
public void attributeReplaced(HttpSessionBindingEvent se) {
//to be extended
}
2. 统计类OnlineStatistics
- /**
- * @author Arantam
- */
- package com.farago.util;
- import java.util.Date;
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.Set;
- import com.farago.vo.MemberInfo;
- /**
- * @author Arantam
- *
- */
- @SuppressWarnings("unchecked")
- public class OnlineStatistics {
- private static int count = 0;
- private static Set onlineMemberList = new HashSet();
- /**
- * 统计在线总数(递增)
- */
- public static void increase() {
- count++;
- }
- /**
- * 统计在线人数(递减)
- */
- public static void decrease() {
- count--;
- }
- /**
- * 统计在线会员(添加)
- *
- * @param memberInfo
- */
- public static void addAttr(MemberInfo memberInfo) {
- // 如果在线会员列表不为空,则迭代该列表,检查当前登录的会员id与列表中的记录id是否一致.
- Iterator itr = onlineMemberList.iterator();
- while (itr.hasNext()) {
- // 先判断该会员是否已有session信息保存在统计对象中.若有,把旧的挤掉,再放入新的.
- MemberInfo temp = (MemberInfo) itr.next();
- String memberName = temp.getName();// 保存在统计类中的用户名
- if (memberInfo.getName().equals(memberName)) {
- itr.remove();
- }
- }
- onlineMemberList.add(memberInfo);
- }
- /**
- * 统计在线会员(清除)
- *
- * @param memberInfo
- */
- public static void removeAttr(MemberInfo memberInfo) {
- onlineMemberList.remove(memberInfo);
- }
- /**
- * 获取在线访客的数量
- *
- * @return the count
- */
- public static int getOnlineVisitors() {
- return count - 1;// 除去管理员本身
- }
- /**
- * 获取在线会员的列表
- *
- * @return the onlineMemberList
- */
- public static Set getOnlineMemberList() {
- return onlineMemberList;
- }
- /**
- * 根据登录时间判断登录次序的先后
- *
- * @param memberInfo
- * @return
- */
- public static boolean isOld(MemberInfo memberInfo) {
- Iterator itr = onlineMemberList.iterator();
- while (itr.hasNext()) {
- MemberInfo temp = (MemberInfo) itr.next();
- String memberName = temp.getName();// 保存在统计类中的用户名
- Date loginTime = temp.getLoginTime();// 保存在统计类中的用户登录时间
- if (memberInfo.getName().equals(memberName) && memberInfo.getLoginTime().before(loginTime)) {
- // 如果当前用户的登录时间比统计对象里保存的同名用户的登录时间要早,则返回true
- return true;
- }
- }
- return false;
- }
- }
/**
* @author Arantam
*/
package com.farago.util;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import com.farago.vo.MemberInfo;
/**
* @author Arantam
*
*/
@SuppressWarnings("unchecked")
public class OnlineStatistics {
private static int count = 0;
private static Set onlineMemberList = new HashSet();
/**
* 统计在线总数(递增)
*/
public static void increase() {
count++;
}
/**
* 统计在线人数(递减)
*/
public static void decrease() {
count--;
}
/**
* 统计在线会员(添加)
*
* @param memberInfo
*/
public static void addAttr(MemberInfo memberInfo) {
// 如果在线会员列表不为空,则迭代该列表,检查当前登录的会员id与列表中的记录id是否一致.
Iterator itr = onlineMemberList.iterator();
while (itr.hasNext()) {
// 先判断该会员是否已有session信息保存在统计对象中.若有,把旧的挤掉,再放入新的.
MemberInfo temp = (MemberInfo) itr.next();
String memberName = temp.getName();// 保存在统计类中的用户名
if (memberInfo.getName().equals(memberName)) {
itr.remove();
}
}
onlineMemberList.add(memberInfo);
}
/**
* 统计在线会员(清除)
*
* @param memberInfo
*/
public static void removeAttr(MemberInfo memberInfo) {
onlineMemberList.remove(memberInfo);
}
/**
* 获取在线访客的数量
*
* @return the count
*/
public static int getOnlineVisitors() {
return count - 1;// 除去管理员本身
}
/**
* 获取在线会员的列表
*
* @return the onlineMemberList
*/
public static Set getOnlineMemberList() {
return onlineMemberList;
}
/**
* 根据登录时间判断登录次序的先后
*
* @param memberInfo
* @return
*/
public static boolean isOld(MemberInfo memberInfo) {
Iterator itr = onlineMemberList.iterator();
while (itr.hasNext()) {
MemberInfo temp = (MemberInfo) itr.next();
String memberName = temp.getName();// 保存在统计类中的用户名
Date loginTime = temp.getLoginTime();// 保存在统计类中的用户登录时间
if (memberInfo.getName().equals(memberName) && memberInfo.getLoginTime().before(loginTime)) {
// 如果当前用户的登录时间比统计对象里保存的同名用户的登录时间要早,则返回true
return true;
}
}
return false;
}
}
3. 拦截器代码片断
- Map sessionMap = invocation.getInvocationContext().getSession();
- if (sessionMap.get("memberInfo") != null) {
- MemberInfo memberInfo = (MemberInfo) sessionMap.get("memberInfo");
- /**
- *
- */
- if (OnlineStatistics.isOld(memberInfo)) {
- sessionMap.remove("memberInfo");// 清除session
- faragoMessage = "对不起,您的帐号[" + memberInfo.getName() + "]已在别的地方登录,您已被迫退出。若有疑问请联系管理员,谢谢!";
- ctx.put("faragoMessage", faragoMessage);
- return Action.ERROR;
- }
- ......
- ...
Map sessionMap = invocation.getInvocationContext().getSession();
if (sessionMap.get("memberInfo") != null) {
MemberInfo memberInfo = (MemberInfo) sessionMap.get("memberInfo");
/**
*
*/
if (OnlineStatistics.isOld(memberInfo)) {
sessionMap.remove("memberInfo");// 清除session
faragoMessage = "对不起,您的帐号[" + memberInfo.getName() + "]已在别的地方登录,您已被迫退出。若有疑问请联系管理员,谢谢!";
ctx.put("faragoMessage", faragoMessage);
return Action.ERROR;
}
......
...
如果想在前台也显示当前在线人数,可以在sessionCreated和sessionDestroyed方法中处理,把统计数字放入ServletContext里面.然后使用S2的标签直接显示.这样来得方便.呵呵