标签:
监听器是实现一个特定的接口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..."); } }
package cn.zq.demo; public interface PersonListener { void run(PersonEvent e); }
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(); } }
在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()); } }
<listener> <listener-class>cn.zq.listener.RequestListener</listener-class> </listener>
request创建了! 这个request是org.apache.catalina.connector.RequestFacade@19845fb request销毁了! 这个request是org.apache.catalina.connector.RequestFacade@19845fb
分析:仅仅要有人訪问,创建一个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); } } }
<listener> <listener-class>cn.zq.filter.MyHttpSessionListener</listener-class> </listener>
<p>在线人数:${applicationScope.onlineCount }</p>
<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@1a8739b name=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)能够踢出某个用户
分析:仅仅要有人登录(输入了username)就会放到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>
(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); } }
<%@ 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中,为了避免訪问次数的丢失。应当将server停止时将訪问次数放到文件里保存,server启动时再从文件里读取,这个操作应当在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>
要监听一个对象是否被绑定到了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中解绑了"); } }
<% Person p = new Person(); session.setAttribute("p", p); session.removeAttribute("p"); %>
这个监听器用处并不大,使用了这个监听器。那么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>
<% if(session.getAttribute("p") == null){ int rand = new Random().nextInt(50); Person p = new Person(); p.setName("p" + rand); session.setAttribute("p", p); } //在浏览器设置这个cookie能确保,下次訪问时。通知server当前的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)測试并查看结果,将每次的结果进行对照。
版权声明:本文博主原创文章。欢迎各转载。转载请注明出处!
标签:
原文地址:http://www.cnblogs.com/gcczhongduan/p/4834163.html