思路,主要是实现一些session监听器的接口,在session中set属性时,判断是不是user对象,然后缓存下来,userName为key,session对象为value,
然后,每次登录的时候去这个缓存中查找是否有这个用户,取出来的session为空则没有,取出来有值,则改用户已登录过了,
后面就是自己的逻辑了。
有2种
1,后登陆的挤掉先登录的,就是把查出来的老的session关闭掉,然后把用户保存到session,内部把现在的用户和其对应的session作为键值对都缓存起来。
2,后登陆的登不上,先登录的一直保持,这个就是登录时查找缓存的用户集合,如果已经有这个用户了,就不让他登录。。
然后要做的就是,session关闭,失效,超时,浏览器关闭(web程序),用户退出等时候要去把缓存的中对应的user-session键值对清除,不然,如果采用第二种方案的话就可能造成用户登不上,因为缓存中还有这个用户。
在这个基础上要实现踢人或者统计在线用户就很简单了,直接取缓存用户的map的长度,或者从缓存用户的map中查找出session,让session失效。。
1,监听器类
package cn.hydom.ztc.ztc_app.controller.listener;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import cn.hydom.ztc.ztc_dao.entity.User;
/
* @Description: session监听器 用户唯一登录,后登陆挤掉先登录的
* @author whl
* @date 2014-10-21
*/
public class SessionListener implements HttpSessionListener,
HttpSessionAttributeListener {
// log4j
private final static Log log = LogFactory.getLog(SessionListener.class);
// 保存当前登录的所有用户
public static Map<String, HttpSession> loginUser = new HashMap<String, HttpSession>();
// 用这个作为session中的key
public static String SESSION_LOGIN_NAME = "user";
// 执行setAttribute的时候, 当这个属性本来不存在于Session中时, 调用这个方法.
@Override
public void attributeAdded(HttpSessionBindingEvent se) {
// 如果添加的属性是用户名, 则加入map中
if (se.getName().equals(SESSION_LOGIN_NAME)) {
User u = (User) se.getValue();
HttpSession session = loginUser.remove(u.getUserName());
if (session != null) {
session.removeAttribute("user");
}
loginUser.put(u.getUserName(), se.getSession());
}
}
// 当执行removeAttribute时调用的方法
@Override
public void attributeRemoved(HttpSessionBindingEvent se) {
// 如果移除的属性是用户名, 则从map中移除
if (se.getName().equals(SESSION_LOGIN_NAME)) {
try {
User u = (User) se.getSession().getAttribute("user");
loginUser.remove(u.getUserName());
} catch (Exception e) {
log.debug(e);
}
}
}
// 当执行setAttribute时 ,如果这个属性已经存在, 覆盖属性的时候, 调用这个方法
@Override
public void attributeReplaced(HttpSessionBindingEvent se) {
// 如果改变的属性是用户名, 则跟着改变map
if (se.getName().equals(SESSION_LOGIN_NAME)) {
User u = (User) se.getValue();
HttpSession session = loginUser.remove(u.getUserName());
/*if (session != null) {
session.removeAttribute("user");
}*/
loginUser.put(u.getUserName(), se.getSession());
}
}
// session创建时调用这个方法
@Override
public void sessionCreated(HttpSessionEvent se) {
log.debug("SessionListener........session创建-----"
+ se.getSession().getId());
}
// Session失效或者过期的时候调用的这个方法,
@Override
public void sessionDestroyed(HttpSessionEvent se) {
// 如果session超时, 则从map中移除这个用户
try {
User u = (User) se.getSession().getAttribute("user");
loginUser.remove(u.getUserName());
} catch (Exception e) {
log.debug(e);
}
}
//写一个判断用户是否已经登陆的方法
public boolean isLogonUser(Long userId) {
Set<HttpSession> keys = SessionListener.loginUser.keySet();
for (HttpSession key : keys) {
if (SessionListener.loginUser.get(key).equals(userId)) {
return true;
}
}
return false;
}
}
2,web.xml中配置监听器类
<listener>
<listener-class>监听器(类)的完全限定名</listener-class>
</listener>
3,用户登录时的逻辑判断
//根据用户名查找,判断是否为空,实现自己的逻辑,挤掉还是不允许登录
Map<String, HttpSession> loginUser = SessionListener.loginUser;