第7章 监听器Listener
Listener概述
Listener的使用
使用Listener需要实现相应的Listener接口。
public class SessionListenerTest implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent se) {
HttpSession session = se.getSession();
System.out.println("新创建了一个session: " + session);
}
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession();
System.out.println("销毁了一个session: " + session);
}
}
以上代码实现了HttpSessionListener接口。创建Session时会是服务器调用SessionCreated()方法,销毁Session时服务器调用sessionDestroyed()方法。他们都以HttpSessionEvent对象为参数,可以从该参数中获取session。Listener需要在web.xml中配置才能生效。
配置如下:
<listener>
<listener-class>
com.helloweenvsfei.listener.SessionListenerTest
</listener-class>
</listener>
Listener的分类
1.监听对象的创建与销毁
HttpSessionListener,HttpContextListener,HttpRequestListener分别用于Session,context,request的创建与销毁。
可以一个类实现多个Listener接口,如下代码:
2.监听对象的属性变化
代码如下:
3.监听Session内的对象
HttpSessionBindingListener和HttpSessionActivationListener
HttpSessionBindingListener:当对象被放到Session时执行valueBound(HttpSessionBinding event)方法,对象被移除时执行valueUnbound(HttpSessionBinding event)方法。对象必须实现该Listener接口。
HttpSessionActivationListener:服务器关闭时,会将Session内的内容保存到硬盘上,这个过程叫钝化。服务器启动时会将硬盘内容加载进来。当Session里的对象被钝化时会执行sessionWillPassivate(HttpSessionEvent event),当对象被加载时执行sessionDidActivate(HttpSessionEvent event)。对象必须实现该listener接口。
Listener使用案例(单态登陆)
public class LoginSessionListener implements HttpSessionAttributeListener {
Log log = LogFactory.getLog(this.getClass());
Map<String, HttpSession> map = new HashMap<String, HttpSession>();
public void attributeAdded(HttpSessionBindingEvent event) {
String name = event.getName();
// 登录
if (name.equals("personInfo")) {
PersonInfo personInfo = (PersonInfo) event.getValue();
if (map.get(personInfo.getAccount()) != null) {
// map 中有记录,表明该帐号在其他机器上登录过,将以前的登录失效
HttpSession session = map.get(personInfo.getAccount());
PersonInfo oldPersonInfo = (PersonInfo) session
.getAttribute("personInfo");
log.info("帐号" + oldPersonInfo.getAccount() + "在"
+ oldPersonInfo.getIp() + "已经登录,该登录将被迫下线。");
session.removeAttribute("personInfo");
session.setAttribute("msg", "您的帐号已经在其他机器上登录,您被迫下线。");
}
// 将session以用户名为索引,放入map中
map.put(personInfo.getAccount(), event.getSession());
log.info("帐号" + personInfo.getAccount() + "在" + personInfo.getIp()
+ "登录。");
}
}
public void attributeRemoved(HttpSessionBindingEvent event) {
String name = event.getName();
// 注销
if (name.equals("personInfo")) {
// 将该session从map中移除
PersonInfo personInfo = (PersonInfo) event.getValue();
map.remove(personInfo.getAccount());
log.info("帐号" + personInfo.getAccount() + "注销。");
}
}
public void attributeReplaced(HttpSessionBindingEvent event) {
String name = event.getName();
// 没有注销的情况下,用另一个帐号登录
if (name.equals("personInfo")) {
// 移除旧的的登录信息
PersonInfo oldPersonInfo = (PersonInfo) event.getValue();
map.remove(oldPersonInfo.getAccount());
// 新的登录信息
PersonInfo personInfo = (PersonInfo) event.getSession()
.getAttribute("personInfo");
// 也要检查新登录的帐号是否在别的机器上登录过
if (map.get(personInfo.getAccount()) != null) {
// map 中有记录,表明该帐号在其他机器上登录过,将以前的登录失效
HttpSession session = map.get(personInfo.getAccount());
session.removeAttribute("personInfo");
session.setAttribute("msg", "您的帐号已经在其他机器上登录,您被迫下线。");
}
map.put("personInfo", event.getSession());
}
}
}
代码详解:
每次用户登录时都会将JavaBean personinfo对象放入到session中,此时会触发监听器LoginSessionListener中的attributeAdded方法,该方法获取personinfo的账号并与已有的map集合中信息比对,看是否有重复的,如果有重复的,则获取重复的session,并去除该session的personinfo信息。
HttpSession session = map.get(personInfo.getAccount());
session.removeAttribute("personInfo");
session.setAttribute("msg", "您的帐号已经在其他机器上登录,您被迫下线。");
以上代码之所以可以去除原有登陆信息的原因如下:
在Java中参数传递都是传的引用,因此Map集合中的session都是原始session的引用。
代码HttpSession session = map.get(personInfo.getAccount());获得的便是原始的session。因此删除该session的personInfo便是删除原始session的personInfo。