概述
监听器(listener):
主要是用来监听特定对象的创建或销毁、属性的变化的!
是一个实现特定接口的普通java类!
对象:
自己创建自己用 (不用监听)
别人创建自己用 (需要监听)
Servlet中哪些对象需要监听?
request / session / servletContext
分别对应的是request监听器、session相关监听器、servletContext监听器
监听器接口:
一、监听对象创建/销毁的监听器接口
Interface ServletRequestListener 监听request对象的创建或销毁
Interface HttpSessionListener 监听session对象的创建或销毁
Interface ServletContextListener 监听servletContext对象的创建或销毁
二、监听对象属性的变化
Interface ServletRequestAttributeListener 监听request对象属性变化: 添加、移除、修改
Interface HttpSessionAttributeListener 监听session对象属性变化: 添加、移除、修改
Interface ServletContextAttributeListener 监听servletContext对象属性变化
三、session相关监听器
Interface HttpSessionBindingListener 监听对象绑定到session上的事件
Interface HttpSessionActivationListener(了解) 监听session序列化及反序列化的事件
生命周期监听器
生命周期监听器: 监听对象的创建、销毁的过程!
监听器开发步骤:
1.写一个普通java类,实现相关接口;
2.配置(web.xml)
ServletRequestListener
监听器类
package com.cn.life;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
/**
* 监听request对象的创建或销毁
* @author liuzhiyong
*
*/
public class MyServletRequestListener implements ServletRequestListener {
/**
* 对象销毁
*/
@Override
public void requestDestroyed(ServletRequestEvent sre) {
//获取request中存放的数据
Object att = sre.getServletRequest().getAttribute("attr1");
System.out.println(att);
System.out.println("MyServletRequestListener.requestDestroyed()");
}
/**
* 对象创建
*/
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("MyServletRequestListener.requestInitialized()");
}
}
web.xml配置
<!-- 监听request对象创建、销毁 -->
<listener>
<listener-class>com.cn.life.MyServletRequestListener</listener-class>
</listener>
ServletContextListener
监听器类
package com.cn.life;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyServletContextListener implements ServletContextListener {
/**
* 创建时
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("................................MyServletContextListener.contextInitialized()");
}
/**
* 销毁时
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("................................MyServletContextListener.contextDestroyed()");
}
}
web.xml配置
<!-- 监听ServletContext对象创建、销毁 -->
<listener>
<listener-class>com.cn.life.MyServletContextListener</listener-class>
</listener>
HttpSessionListener
监听器类
package com.cn.life;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class MyHttpSessionListener implements HttpSessionListener {
/**
* 创建
*/
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("MyHttpSessionListener.sessionCreated()");
}
/**
* 销毁
*/
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("MyHttpSessionListener.sessionDestroyed()");
}
}
web.xml配置
<!-- 监听Session对象创建、销毁 -->
<listener>
<listener-class>com.cn.life.MyHttpSessionListener</listener-class>
</listener>
属性监听器
属性监听器: 监听属性的变化!
监听器开发步骤:
1.写一个普通java类,实现相关接口;
2.配置(web.xml)
ServletRequestAttributeListener
监听器类
package com.cn.attribute;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
/**
* 监听request属性
* @author liuzhiyong
*
*/
public class MyServletRequestAttributeListener implements
ServletRequestAttributeListener {
@Override
public void attributeAdded(ServletRequestAttributeEvent srae) {
System.out
.println("MyServletRequestAttributeListener.attributeAdded()");
System.out.println("获取添加的属性值" + srae.getServletRequest().getAttribute("attr1"));
}
@Override
public void attributeRemoved(ServletRequestAttributeEvent srae) {
System.out
.println("MyServletRequestAttributeListener.attributeRemoved()");
}
@Override
public void attributeReplaced(ServletRequestAttributeEvent srae) {
System.out
.println("MyServletRequestAttributeListener.attributeReplaced()");
}
}
web.xml配置
<!-- 监听request属性 -->
<listener>
<listener-class>com.cn.attribute.MyServletRequestAttributeListener</listener-class>
</listener>
HttpSessionAttributeListener
监听器类
package com.cn.attribute;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
public class MyHttpSessionAttributeListener implements
HttpSessionAttributeListener {
@Override
public void attributeAdded(HttpSessionBindingEvent se) {
System.out.println("添加session属性值" + se.getSession().getAttribute("attr2"));
System.out.println("MyHttpSessionAttributeListener.attributeAdded()");
}
@Override
public void attributeRemoved(HttpSessionBindingEvent se) {
System.out.println("移除session属性值" + se.getSession().getAttribute("attr2"));
System.out.println("MyHttpSessionAttributeListener.attributeRemoved()");
}
@Override
public void attributeReplaced(HttpSessionBindingEvent se) {
//获取session对象
HttpSession session = se.getSession();
//获取替换前的值
Object oldValue = se.getValue();
System.out.println("session原来的属性值" + oldValue);
//获取新值
Object newValue = session.getAttribute("attr2");
System.out.println("session新的属性值" + newValue);
}
}
web.xml配置
<!-- 监听session属性 -->
<listener>
<listener-class>com.cn.attribute.MyHttpSessionAttributeListener</listener-class>
</listener>
其他监听器:session相关监听器
HttpSessionBindingListener
监听对象绑定/解除绑定到sesison上的事件!
步骤:
对象实现接口; 再把对象绑定/解除绑定到session上就会触发监听代码。
作用:
(上线提醒!)
思考:这个session监听器,和上面的声明周期、属性监听器区别?
不用再web.xml配置,因为监听的对象是自己创建的对象,不是服务器对象!
package com.cn.session;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
/**
* 监听此对象绑定到session上的过程,需要实现特定接口HttpSessionBindingListener
* @author liuzhiyong
*
*/
public class User implements HttpSessionBindingListener{
private int id;
private String userName;
private String pwd;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public User() {
}
public User(int id, String userName, String pwd) {
super();
this.id = id;
this.userName = userName;
this.pwd = pwd;
}
/**
* 对象放入session
*/
@Override
public void valueBound(HttpSessionBindingEvent event) {
HttpSession session = event.getSession();
System.out.println("对象放入session中");
}
/**
* 对象从session中移除
*/
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
System.out.println("对象从session中移除");
}
}
案例
需求:
做一个在线列表提醒的功能!
用户 -> 登陆
-> 显示登陆信息,列表展示。(list.jsp)
-> 显示在线用户列表 (list.jsp)
-> 列表点击进入“在线列表页面” onlineUser.jsp
实现思路:
1.写监听器,监听servletContext对象的创建: 初始化集合(onlineUserList)
2.登陆功能:用户登陆时候,把数据保存到servletContext中
3.退出功能: 销毁当前session
3
.写监听器:监听session销毁,把当前登陆用户从onlineUserList移除!
4.list.jsp 增加超链接, 点击时候提交直接跳转到onlineUserList.jsp
核心代码:
监听servletContext对象的创建: 初始化在线列表集合(onlineuserlist)
package com.cn.listener;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import com.cn.entity.User;
/**
* 监听servletContext对象的创建: 初始化在线列表集合(onlineuserlist)
* @author liuzhiyong
*
*/
public class OnlineUserListener implements ServletContextListener {
/**
* 监听servletContext对象的创建
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
/**
* 创建集合,存放在线用户
* 每次当用户登陆后,就往这个集合中添加当前登陆者
*/
List<User> onlineUserList = new ArrayList<User>();
//放入servletContext中
sce.getServletContext().setAttribute("onlineUserList", onlineUserList);
}
/**
* 监听servletContext对象的销毁
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
//获取ServletContext
ServletContext sc = sce.getServletContext();
//获取在线列表
Object obj = sc.getAttribute("onlineList");
//移除在线刘表集合
if(obj != null){
sc.removeAttribute("onlineList");
}
}
}
登陆功能:用户登陆时候,把数据保存到servletContext中
package com.cn.servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.cn.entity.User;
import com.cn.service.UserService;
import com.cn.service.impl.UserServiceImpl;
/**
* 登录控制层
* @author liuzhiyong
*
*/
public class LoginServlet extends HttpServlet {
//Service实例
private UserService service = new UserServiceImpl();
//跳转资源
private String uri;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
//获取请求参数
String email = request.getParameter("email");
String pwd = request.getParameter("pwd");
//封装
User user = new User();
user.setEmail(email);
user.setPwd(pwd);
//调用Service处理业务
User userInfo = service.findByEmailAndPwd(user);
//判断
if(userInfo!= null){
/*
* 登录成功
*/
//保存登录数据到session
request.getSession().setAttribute("userInfo", userInfo);
/**
* 在线列表功能:
* 1.先从ServletContext中获取在线列表集合(onlineList)
* 2.用户登陆时候,把当前用户数据保存到“在线列表集合”中
*/
//得到servletContext对象
ServletContext sc = request.getServletContext();
//获取在线列表集合
List<User> onlineUserList = (ArrayList<User>)sc.getAttribute("onlineUserList");
//添加当前登录者
onlineUserList.add(userInfo);
//保存当前登录者到ServletContext中
// sc.setAttribute("onlineUserList", onlineUserList);//这里可以不写,因为对象引用传递
//跳转到首页Servlet
uri = "/ListServlet";
}else{
/**
* 登录失败
*/
//将用户输入的数据放入request域对象中
request.setAttribute("email", email);
//保存提示信息到request域对象中
request.setAttribute("msg", "密码或账号错误!");
//转发到登录页面
uri = "/login.jsp";
}
} catch (Exception e) {
//测试
e.printStackTrace();
//错误页面
uri = "/error/error.jsp";
}
//跳转
request.getRequestDispatcher(uri).forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
退出功能:当前session销毁
package com.cn.servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.cn.entity.User;
/**
* 退出功能:当前session销毁
* @author liuzhiyong
*
*/
public class OutServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取当前用户session中当前用户的信息
HttpSession session = request.getSession(false);
User userInfo = (User)session.getAttribute("userInfo");
//移除session中属性为“userInfo”的用户信息
// session.removeAttribute("userInfo");//这里不删,因为监听器中需要获取,不能删,只用销毁session了,就能调用session监听器
//销毁session
session.invalidate();
//跳转到登录页
response.sendRedirect(request.getContextPath()+"/login.jsp");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);
}
}
写监听器:监听session销毁,把当前登陆用户从onlineUserList移除!
package com.cn.listener;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import com.cn.entity.User;
/**
* 监听服务器session销毁的动作:session.invalid();
* 当session销毁的时候,从在线列表集合中移除当前的登录用户
* @author liuzhiyong
*
*/
public class SessionInvalidListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
// TODO Auto-generated method stub
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("。。。。。。。。。。。。。。。。。。。。。。session销毁一个。。。。。。。。。。。。。。。。。。。");
//获取当前销毁的session对象
HttpSession session = se.getSession();
//获取session中userInfo的属性
User userInfo = (User)session.getAttribute("userInfo");
//获取ServletContext对象
ServletContext sc = session.getServletContext();
//获取ServletContext中的在线用户列表
List<User> onlineUserList = (ArrayList<User>)sc.getAttribute("onlineUserList");
//删除当前登录者
if(userInfo != null){
onlineUserList.remove(userInfo);
}
//保存当前登录者到ServletContext中
// sc.setAttribute("onlineUserList", onlineUserList);//这里可以不写,因为对象引用传递
}
}