关于同一用户不能同时登录问题的探讨(2/2)
前言
这是一些理论的东西,大概包括httpsession监听的执行时机,以及相对应的attribute监听的机制调用,并写一些相应的实现sample.
正文
监听器概述:
1.Listener是Servlet的监听器
2.可以监听客户端的请求、服务端的操作等。
3.通过监听器,可以自动激发一些操作,如监听在线用户数量,当增加一个HttpSession时,给在线人数加1。
4.编写监听器需要实现相应的接口
5.编写完成后在web.xml文件中配置一下,就可以起作用了
6.可以在不修改现有系统基础上,增加web应用程序生命周期事件的跟踪
常用的监听接口:
1.ServletContextAttributeListener
监听对ServletContext属性的操作,比如增加/删除/修改;
2.ServletContextListener
监听ServletContext,当创建ServletContext时,激发contextInitialized (ServletContextEvent sce)方法;当销毁ServletContext时,激发contextDestroyed (ServletContextEvent sce)方法。
3.HttpSessionListener
监听HttpSession的操作。当创建一个Session时,激发session Created(SessionEvent se)方法;当销毁一个Session时,激发sessionDestroyed (HttpSessionEvent se)方法(但是,如果用户关闭浏览器的话,不会马上调用sessionDestroyed方法,只有等到session过期才会调用,默认为30分)。
4.HttpSessionAttributeListener
监听HttpSession中的属性的操作。当在Session增加一个属性时,激发attributeAdded (HttpSessionBindingEvent se) 方法;当在Session删除一个属性时,激发attributeRemoved (HttpSessionBindingEvent se)方法;当在Session属性被重新设置时,激发attributeReplaced (HttpSessionBindingEvent se) 方法。
实现sample:
1. 由Context监听器管理共享数据库连接,生命周期事件的一个实际应用由context监听器管理共享数据库连接。
在web.xml中如下定义监听器:
<listener> <listener-class>XXX.MyConnectionManager</listener-class> </listener>
创建监听器的实例,接受事件并自动判断实现监听器接口的类型。要记住的是由于监听器是配置在部署描述符web.xml中,所以不需要改变任何代码就可以添加新的监听器。
import java.sql.Connection; import java.sql.SQLException; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class MyConnectionManager implements ServletContextListener { public void contextInitialized(ServletContextEvent e) { Connection con = null;// create connection; e.getServletContext().setAttribute("con", con); } public void contextDestroyed(ServletContextEvent e) { Connection con = (Connection) e.getServletContext().getAttribute("con"); try { con.close(); } catch (SQLException ignored) { } // close connection } }
监听器保证每新生成一个servlet context都会有一个可用的数据库连接,并且所有的连接对会在context关闭的时候随之关闭。
2.HttpSessionListener监听
在web.xml中如下定义监听器:
<listener> <listener-class>org.bromon.test.SessionCount</listener-class> </listener>
代码:
package org.bromon.test; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class SessionCount implements HttpSessionListener { private static int count = 0; public void sessionCreated(HttpSessionEvent se) { count++; System.out.println("session创建:" + new java.util.Date()); } public void sessionDestroyed(HttpSessionEvent se) { count--; System.out.println("session销毁:" + new java.util.Date()); } public static int getCount() { return (count); } }
这里需要注意的是:sessionDestroyed是在session超时或调用session.invalidate就会执行,也就是说当浏览器异常关闭时,session不会马上消失的,而是要等过期或者调用了invalidate方法后才会调用sessionDestoryed方法。
3.HttpSessionAttributeListener监听
设置web.xml文件:
<listener> <listener-class>com.horizon.test.OnlineList</listener-class> </listener>
代码:
package com.horizon.test; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; public class OnlineList implements HttpSessionAttributeListener { private static Map<String, String> map = new HashMap<String, String>(); public void attributeAdded(HttpSessionBindingEvent se) { System.out.println("login"); } public void attributeRemoved(HttpSessionBindingEvent se) { System.out.println("logout"); } public void attributeReplaced(HttpSessionBindingEvent se) { } public static Map<String, String> getMap() { return (map); } }
4.servlet与ajax:
jsp片段代码:
<script type="text/javascript" src="js/jquery-1.8.0.min.js"></script> <script type="text/javascript"> $(function() { setInterval(sub, 500); }); function sub() { $.ajax({ type : "post",//请求方式 url : "SysServlet",//发送请求地址 data : {//发送给数据库的数据 method : "out" }, //请求成功后的回调函数有两个参数 success : function(data, textStatus) { $("#resText").append("<br/>" + data); }, error : function(){ $("#resText").append("<br/>" + "服务器已经断开"); } }); } </script>
servlet代码:
package com.horizon.action; import java.io.IOException; import java.io.PrintWriter; 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.horizon.test.OnlineList; public class SysServlet extends HttpServlet { private static final long serialVersionUID = 1L; public SysServlet() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); HttpSession session = request.getSession(); String method = request.getParameter("method"); if ("login".equals(method)) { login(request, response); } else if ("logout".equals(method)) { System.out.println(session.getAttribute("username")); logout(request, response); } else { System.out.println(session.getAttribute("username")); session.setMaxInactiveInterval(1); System.out.println("start............"); PrintWriter out = response.getWriter(); out.write(">>>>>>>>>>>"); out.flush(); out.close(); } } protected void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); String username = request.getParameter("username"); session.setAttribute("username", username); String uname = OnlineList.getMap().get(username); if ("name".equals(uname)) { response.sendRedirect("error.jsp"); return; } OnlineList.getMap().put(username, "name"); response.sendRedirect("main.jsp"); session.setMaxInactiveInterval(1); } protected void logout(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession sessions = request.getSession(false);// 防止创建Session OnlineList.getMap().remove(sessions.getAttribute("username")); sessions.removeAttribute("username"); response.sendRedirect("index.jsp"); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
写的就这些了,望各位看官,交流意见......其中理论部分有网上查的东西....