监听器就是实现一个特定接口的java程序,此程序专门用来监听另一个类方法的调用。java的awt大量的运用到了此种模式,例如可以给button对象添加一个点击事件,当鼠标点击时,就会调用事件处理程序。又如:在javascript事件中也运用到了此种模式,当用户点击鼠标时,会触发一个鼠标点击事件去调用程序员定义的事件处理程序。下面就以GUI编程来说明监听器。监听器都使用到了观察者模式,观察者模式所定义的对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖他的对象都会得到通知自动更新。
package cn.zq.demo;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class DemoFrame extends JFrame{
/** * */
private static final long serialVersionUID = -7552482706279772458L; public DemoFrame() {
JButton button = new JButton("点击试试");
System.out.println("button ->" + button.hashCode());
//设置默认的关闭操作:关闭时退出程序
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//给button添加一个监听器
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("监听到了 ->"+e.getSource().hashCode());
}
});
//拿到容器
Container container = getContentPane(); //设置为流式布局
container.setLayout(new FlowLayout());
container.add(button);
setSize(200, 100);
setVisible(true);
}
public static void main(String[] args) {
new DemoFrame();
}
}
用button.addActionListener方法给按钮添加了一个监听器,当用户点击鼠标时,监听器中的actionPerformed(ActionEvent e)方法就会被执行,传过来的参数ActionEvent对象包含了当前正在被监听的对象。监听器存在以下三个类:
被监听Person
package cn.zq.demo;
public class Person {
private PersonListener l;
public void addPersonListener(PersonListener l){ this.l = l;
}
public void run() {
//先执行监听器对象方法
if(l != null){ //传递事件源对象
l.run(new PersonEvent(this));
}
System.out.println("Person->"+this + "->run...");
}
}
监听器PersonListener
package cn.zq.demo;
public interface PersonListener {
void run(PersonEvent e);
}
监听到的事件PersonEvent
package cn.zq.demo;
public class PersonEvent {
private Object src;
//构造事件对象时把被监听对象传进来
public PersonEvent(Object src) {
this.src = src;
}
public Object getSource(){
return src;
}
}
测试类:
package cn.zq.demo;
public class Main {
public static void main(String[] args) {
Person p = new Person();
p.addPersonListener(new PersonListener() {
public void run(PersonEvent e) {
System.out.println("event->"+e.getSource() + "->run....");
}
});
//触发用户的run方法
p.run();
}
}
当调用Person.run()方法时,首先会执行PersonListener.run()方法,再调用时会将PersonEvent事件对象传递进来,这个对象包含了当前的Person对象。
在javaweb中主要监听这三个对象:ServletContext. HttpSession, ServletRequest,
主要的监听器如下表:
第一步:创建一个类,这个类实现ServletRequestListener
package cn.zq.listener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
public class RequestListener implements ServletRequestListener{
public void requestInitialized(ServletRequestEvent e) {
System.out.println("request创建了!");
System.out.println("这个request是"+e.getServletRequest());
}
public void requestDestroyed(ServletRequestEvent e) {
System.out.println("request销毁了!");
System.out.println("这个request是"+e.getServletRequest());
}
}
第二步:在web.xml文件中配置
<listener>
<listener-class>cn.zq.listener.RequestListener</listener-class>
</listener>
第三步:部署,启动tomcat,查看结果
request创建了!
这个request是org.apache.catalina.connector.RequestFacade@19845fbrequest销毁了!
这个request是org.apache.catalina.connector.RequestFacade@19845fb
注意:配置listener时只需提供一个类名就行了,tomcat启动时会根据其类型自动的加载,和Servlet, Filter一样,Listener也是单例的,也就是在tomcat容器中只会加载一次。
分析:只要有人访问,创建一个session就是一个会话,一个会话就是一个在线人数。所以需要监听session的创建和销毁。
第一步:编写一个类实现HttpSessionListener接口
package cn.zq.listener;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class MyHttpSessionListener implements HttpSessionListener{ public void sessionCreated(HttpSessionEvent e) {
System.out.println("有人访问本站点了...");
HttpSession session = e.getSession();
System.out.println("session->"+session+"("+session.getId()+")");
ServletContext sc = session.getServletContext();
Integer onlineCount = (Integer) sc.getAttribute("onlineCount"); if(onlineCount == null){
onlineCount = 0;
}
sc.setAttribute("onlineCount", ++onlineCount);
}
public void sessionDestroyed(HttpSessionEvent e) {
System.out.println("有人退出了 ->"+e.getSession().getId());
ServletContext sc = e.getSession().getServletContext();
Integer onlineCount = (Integer) sc.getAttribute("onlineCount"); if(onlineCount != null && onlineCount > 0){
sc.setAttribute("onlineCount", --onlineCount);
}
}
}
第二步:在web.xml文件中配置
<listener>
<listener-class>cn.zq.filter.MyHttpSessionListener</listener-class>
</listener>
第三步:在jsp文件中加入:
<p>在线人数:${applicationScope.onlineCount }</p>
为了能让测试快点看到效果,应该在web.xml文件中配置session存活的时间:
<session-config>
<!-- 分钟 -->
<session-timeout>1</session-timeout>
</session-config>
第一步:编写一个类实现HttpSessionAttributeListener
package cn.zq.listener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;/** * 监听session属性变化 * @author zq * */public class SessionAttributeListener implements HttpSessionAttributeListener{
/**
* 属性被添加后执行此方法
*/
public void attributeAdded(HttpSessionBindingEvent event) {
System.out.println("添加session属性");
HttpSession session = event.getSession();
System.out.println("session ->" + session); //属性名
String name = event.getName(); //属性值
Object value = event.getValue();
System.out.println(name + "=" + value);
}
/**
* 属性被移除时执行这个方法
*/
public void attributeRemoved(HttpSessionBindingEvent event) {
System.out.println("移除session属性");
HttpSession session = event.getSession();
System.out.println("session ->" + session); //属性名
String name = event.getName(); //属性值
Object value = event.getValue();
System.out.println(name + "=" + value);
}
public void attributeReplaced(HttpSessionBindingEvent event) {
System.out.println("替换session属性");
HttpSession session = event.getSession();
System.out.println("session ->" + session); //属性名
String name = event.getName(); //属性值
Object value = event.getValue();
System.out.println("替换前:"+name + "=" + value);
System.out.println("替换后:"+name + "=" + session.getAttribute(name));
}
}
第二步:在web.xml中配置这个监听器
<listener>
<listener-class>cn.zq.listener.SessionAttributeListener</listener-class>
</listener>
第三步:测试
<%
session.setAttribute("name", "RiccioZhang");
session.setAttribute("name", "zq");
session.removeAttribute("name");
%>
添加session属性session ->org.apache.catalina.session.StandardSessionFacade@1a8739bname=RiccioZhang
替换session属性
session ->org.apache.catalina.session.StandardSessionFacade@1a8739b
替换前:name=RiccioZhang
替换后:name=zq
移除session属性
session ->org.apache.catalina.session.StandardSessionFacade@1a8739b
name=zq
(1)显示登录人数
(2)显示登录人的ip,session的创建时间、最后访问时间
(3)可以踢出某个用户
分析:只要有人登录(输入了用户名)就会放到session中,Session.setAttribute("user", "zq");
实现第一个核心类:
package cn.zq.listener;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
public class MySessionAttrListener implements HttpSessionAttributeListener{
public void attributeAdded(HttpSessionBindingEvent event) {
String name = event.getName();
if("user".equals(name)){
ServletContext sc = event.getSession()
.getServletContext();
//将session缓存到map中
@SuppressWarnings("unchecked")
Map<String, HttpSession> m = (Map<String, HttpSession>) sc.getAttribute("login"); if(m == null){
m = new HashMap<String, HttpSession>();
sc.setAttribute("login", m);
}
m.put(event.getSession().getId(), event.getSession());
}
}
public void attributeRemoved(HttpSessionBindingEvent event) {
String name = event.getName(); if("user".equals(name)){
HttpSession session = event.getSession();
ServletContext sc = session.getServletContext();
@SuppressWarnings("unchecked")
Map<String, HttpSession> m = (Map<String, HttpSession>) sc.getAttribute("login"); if(m != null){
m.remove(session.getId());
}
}
} public void attributeReplaced(HttpSessionBindingEvent event) {}
}
配置:
<listener>
<listener-class>cn.zq.listener.MySessionAttrListener</listener-class>
</listener>
开发登录,退出功能:
(1)登录页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>
<head>
<title>主页</title>
</head>
<body>
<c:choose>
<c:when test="${empty sessionScope.user}">
<form action="<c:url value='/Login'/>" method="post">
<input type="text" name="name"><br/>
<input type="submit" >
</form>
</c:when>
<c:otherwise>
欢迎您,${sessionScope.user }<br/>
<a href="<c:url value='/Login'/>">退出</a><br/>
</c:otherwise>
</c:choose>
<a href="<c:url value='/ShowServlet'/>">显示所有登录人数</a>
</body></html>
(2)开发处理登录、退出的servlet
package cn.zq.servlet;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 3059445154848670189L; public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.getSession()
.removeAttribute("user");
response.sendRedirect(request.getContextPath() + "/index.jsp");
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String name = request.getParameter("name");
request.getSession().setAttribute("user", name);
request.getSession().setAttribute("ip", request.getRemoteAddr());
response.sendRedirect(request.getContextPath() + "/index.jsp");
}
}
配置:
<servlet>
<servlet-name>ShowServlet</servlet-name>
<servlet-class>cn.zq.servlet.ShowServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/Login</url-pattern>
</servlet-mapping>
开发转换登录人集合数据的servlet和显示登录人信息的页面
(1)获取登录人集合并将其转换成一个MapList,将封装好的信息传递到显示页面
package cn.zq.servlet;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
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;
public class ShowServlet extends HttpServlet { /** * */
private static final long serialVersionUID = 8867391453104991999L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext sc = getServletContext(); @SuppressWarnings("unchecked")
Map<String, HttpSession> m = (Map<String, HttpSession>)
sc.getAttribute("login");
List<Map<String, Object>> list = new ArrayList<Map<String,Object>>(); if(m != null){
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); for(Iterator<Map.Entry<String, HttpSession>> it = m.entrySet().iterator();
it.hasNext();){
Entry<String, HttpSession> entry = it.next();
Map<String, Object> mapBean = new HashMap<String, Object>();
mapBean.put("sessionid", entry.getKey());
mapBean.put("user", entry.getValue().getAttribute("user"));
mapBean.put("creationTime", df.format(new Date(entry.getValue().getCreationTime())));
mapBean.put("lastAccessTime", df.format(new Date(entry.getValue().getLastAccessedTime())));
mapBean.put("ip", entry.getValue().getAttribute("ip"));
list.add(mapBean);
}
}
request.setAttribute("list", list);
request.getRequestDispatcher("/page/show.jsp")
.forward(request, response);
}
}
(2)显示页面取出数据显示
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%><%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>
<head>
<title>显示登录人数</title>
</head>
<body>
<p>欢迎您:<c:out value="${user }"></c:out>,共${fn:length(list) }人,以下是所有登录人数:</p>
<table border="1">
<tr>
<th>姓名</th>
<th>登录时间</th>
<th>最后访问时间</th>
<th>登录ip</th>
<th>操作</th>
</tr>
<c:forEach items="${list}" var="m">
<tr>
<td>${m.user}</td>
<td>${m.creationTime}</td>
<td>${m.lastAccessTime}</td>
<td>${m.ip}</td>
<td>
<a href="<c:url value='/KickupServlet?id=${m.sessionid }'/>">踢出</a>
</td>
</tr>
</c:forEach>
</table>
</body></html>
开发第二个核心类,实现将用户踢出的功能
package cn.zq.servlet;
import java.io.IOException;
import java.util.Map;
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;
public class KickupServlet extends HttpServlet {
private static final long serialVersionUID = 1007302413238302848L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String id = request.getParameter("id");
ServletContext sc = getServletContext();
Map<String, HttpSession> login = (Map<String, HttpSession>) sc.getAttribute("login");
HttpSession session = login.get(id); if(session != null){
session.removeAttribute("user");
}
login.remove(id);
response.sendRedirect(request.getContextPath() + "/ShowServlet");
}
}
配置:
<servlet>
<servlet-name>KickupServlet</servlet-name>
<servlet-class>cn.zq.servlet.KickupServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>KickupServlet</servlet-name> <url-pattern>/KickupServlet</url-pattern> </servlet-mapping>
完成以上步骤,并测试自己写的程序。
这个监听器很有用,比如可以在web容器启动的是否加载一些配置文件,执行一些初始化操作,web容器停止时,执行一些清楚操作。spring就是使用监听器在web容器启动时执行初始化的。
ServletContextListener有2个方法:
做一个案例:开发一个显示网站的访问次数的小功能
分析:应该将访问次数存放到servletContext中,为了避免访问次数的丢失,应当将服务器停止时将访问次数放到文件中保存,服务器启动时再从文件中读取,这个操作应当在ServletContextListener监听器中做。用户每发送一次请求就算是一次访问,记录访问次数的增加,可以再过滤器中做,也可以在ServletRequestListener中做(创建一个request对象就是一次访问),因为在学习监听器,所以我选择后者。
(1)开发一个ServletContextListener和一个ServletRequestListener
package cn.zq.listener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyServletContextListener implements ServletContextListener{
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContext:"+sce.getServletContext()+"->init...");
String path = MyServletContextListener.class.getClassLoader().getResource("vist.txt").getFile(); try {
BufferedReader br = new BufferedReader(new FileReader(path));
String line = br.readLine(); long vistCount = 0; if(line != null && line.length() > 0){
vistCount = Long.parseLong(line);
}
sce.getServletContext().setAttribute("vistCount", vistCount);
System.out.println("初始化的访问次数:"+vistCount);
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext:"+sce.getServletContext()+"->destroy...");
String path = MyServletContextListener.class.getClassLoader().getResource("vist.txt").getFile(); try {
FileWriter fw = new FileWriter(path);
Long vistCount = (Long) sce.getServletContext()
.getAttribute("vistCount"); if(vistCount != null){
fw.write(vistCount.toString());
}
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package cn.zq.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
public class RequestListener implements ServletRequestListener {
public void requestInitialized(ServletRequestEvent e) {
System.out.println(e.getServletRequest()+"->创建了");
ServletContext sc = e.getServletContext();
Long vistCount = (Long) sc.getAttribute("vistCount"); if(vistCount == null){
vistCount = 0L;
}
sc.setAttribute("vistCount", ++vistCount);
}
public void requestDestroyed(ServletRequestEvent e) {
System.out.println(e.getServletRequest() + "->销毁了");
}
}
配置:
<listener>
<listener-class>cn.zq.listener.RequestListener</listener-class>
</listener>
<listener>
<listener-class> cn.zq.listener.MyServletContextListener</listener-class>
</listener>
(2)从jsp页面获取访问次数,测试tomcat正常停止后,再次启动是否能读取到以前 访问次数。
要监听一个对象是否被绑定到了session对象中,这个对象需要实现HttpSessionbindingListener这个接口,注意:只需要实现这个接口,不需要配置到web.xml文件中。
(1)先开发一个Person类实现这个接口
package cn.zq.domain;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
public class Person implements HttpSessionBindingListener{
public void valueBound(HttpSessionBindingEvent event) {
String name = event.getName();
Object value = event.getValue();
System.out.println(value+"被绑定到session中了");
System.out.println(name + "=" + value);
}
public void valueUnbound(HttpSessionBindingEvent event) {
System.out.println(event.getValue()+"从session中解绑了");
}
}
(2)在jsp中加入如下代码
<%
Person p = new Person();
session.setAttribute("p", p);
session.removeAttribute("p");
%>
(3)测试,并查看结果
这个监听器用处并不大,使用了这个监听器,那么javabean就与这个接口耦合起来了,增加了耦合度,那么意味着这个javabean就必须依赖servel api而存在,没有了就会出现错误
实现此接口的javabean可以感知活化(从硬盘到内存)或钝化(从内存到硬盘)的过程,如果同时需要保存在session中的javabean,则此javabean需要实现Serializable接口,实现此接口的javabean,不需要配置到web.xml文件中。在session被活化或钝化时,保存在session中的相应javabean执行的方法。
(1)编写一个Person类实现此接口,并且实现序列化接口
package cn.zq.domain;
import java.io.Serializable;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;
public class Person implements HttpSessionActivationListener,
Serializable{
private static final long serialVersionUID = 7606213806247294106L;
private String name;
public Person(String name) {
this.name = name;
}
public Person() {}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return "Person [name=" + name + "]";
}
public void sessionDidActivate(HttpSessionEvent e) {
System.out.println("------------------------");
System.out.println(this+"活了...");
System.out.println("这个session是"+e.getSession());
}
public void sessionWillPassivate(HttpSessionEvent e) {
System.out.println("------------------------");
System.out.println(this+"钝化了...");
System.out.println("这个session是"+e.getSession());
}
}
(2)在tomcat的目录下的conf\Catalina\localhost配置这个项目
<Context docBase="D:\\code\\j2ee\\listener\\WebRoot">
<Manager className="org.apache.catalina.session.PersistentManager"
saveOnRestart="true">
<Store className="org.apache.catalina.session.FileStore"
directory="c:/a">
</Store>
</Manager>
</Context>
(3)编写测试jsp
<% if(session.getAttribute("p") == null){ int rand = new Random().nextInt(50); Person p = new Person(); p.setName("p" + rand); session.setAttribute("p", p); } //在浏览器设置这个cookie能确保,下次访问时,通知服务器当前的cookie Cookie cookie = new Cookie("JSESSIONID", session.getId()); cookie.setMaxAge(60*10); cookie.setPath(request.getContextPath()); response.addCookie(cookie); %>
${p } <hr/>
<%=session.getId() %>
<hr/>
(4)测试并查看结果,将每次的结果进行对比。
作者:RiccioZhang
出处:https://blog.csdn.net/ricciozhang/article/details/43833401
觉得有用就转发分享一下吧