`
酷的飞上天空
  • 浏览: 521816 次
  • 性别: Icon_minigender_1
  • 来自: 无锡
社区版块
存档分类
最新评论

sessionDestroyed执行时间的奇怪问题

    博客分类:
  • J2EE
阅读更多

问题描述:

用户登陆后转到list.jsp页面,此页面不停向服务器请求数据。用户的登录名保存到session和servletContext的用户列表中一个list。当用户session失效的时候从用户列表中删除用户。

问题是:

虽然不停向服务器发送数据,但还是会在不到一分钟的时间内调用sessionDestroyed方法,难道此方法不是在session失效的时候才被调用?

 

下面贴出完整代码。

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>login</title>
</head>
<body style="text-align: center;">

	<p style="margin-top: 200px;" />
	<p>${error }</p>
	<form action="login" method="post">
		用户名:<input type="text" name="name"/>
		<p/>
		<input type="submit"/>
	</form>
</body>
</html>

 

 LoginServlet

public class LoginServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		req.setCharacterEncoding("UTF-8");
		String name = req.getParameter("name");
		List<String> list;
		if(name==null||name.equals("")){
			req.setAttribute("error", "登录名不能为空!");
			req.getRequestDispatcher("login.jsp").forward(req, resp);
			return;
		}
		//从ServletContext中取得已登录用户信息的容器,一个list
		Object o = getServletContext().getAttribute("list");
		if(o==null){
			//如果没有,则创建一个并放入ServletContext
			list = new ArrayList();
			getServletContext().setAttribute("list", list);
		}
		else {
			//有则返回
			list = (List<String>)o ;
		}
		//如果当前登陆用户有重名的则,无法登陆
		if(list.contains(name)){
			req.setAttribute("error", "用户已存在!");
			req.getRequestDispatcher("login.jsp").forward(req, resp);
			return;
		}
		//将登陆用户放入ServletContext中的list
		list.add(name);
		getServletContext().setAttribute("list", list);
		//将当前用户的用户名放入session
		HttpSession session = req.getSession();
		Logger.getLogger(this.getClass().getName()).info("原始会话超时时间为:"+session.getMaxInactiveInterval());
		session.setMaxInactiveInterval(5); //设置当前会话的失效时间,单位是秒。即5秒不回应则判定离线
		session.setAttribute("name", name);
		Logger.getLogger(this.getClass().getName()).info("设定会话超时时间为:"+session.getMaxInactiveInterval());
		
		req.setAttribute("list", list);

		req.getRequestDispatcher("list.jsp").forward(req, resp);
		
	}
}

 list.jsp ,用到了jquery进行Ajax调用

  

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.util.*" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>login</title>
<style type="text/css">
	.left{
		width: 200px;
		height: 600px;
		float: left;
		border: dashed 1px black;
	}
	.right{
		width: 600px;
		height: 600px;	
		margin-left: 220px;
		border: dotted 1px black;
		overflow: scroll;
	}
</style>
<script type="text/javascript" src="jquery-1.4.2.min.js"></script>
<script type="text/javascript">
	//如果返回类型定义为json,则无法重复执行,所以只能自己eval了。原因是jquery1.4解析json格式比较严格,这里返回的是不严格的json格式,致使解析失败。解决方法:1.返回严格的json格式数据2.自己eval生成json对象
	$(function(){
		function getText(){
			$.post("control",function(data){
				var json = eval("("+data+")");
				//返回在线用户数组
				var list = json.list;
				var date = json.date; //服务器端返回的日期
				var $left = $(".left");
				var nameList = "";  //构造用户在线字符串形式,方便添加进html
				for(var i in list){
					nameList = nameList+"<li>"+list[i]+"</li>"
				}
				$left.empty().html("当前用户列表:<br/><ul>"+nameList+"</ul>");
				$(".right").append("服务器端传来数据:"+date+'<br/>');
				//继续请求服务器
				getText();
			});
		}
		//开始执行
		getText();
	});
</script>
</head>
<body>
<div class="left">
当前用户列表:
<p></p>
<ul>
	<%
		List<String> list = (List<String>)request.getAttribute("list");
		for(String s:list){
	%>
		<li><%=s %></li>
		<%} %>
</ul>
</div>
<div class="right">

</div>
</body>
</html>

   ControlServlet

 

public class ControlServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String text;
		List<String> list;
		StringBuilder sb = new StringBuilder();
		text = simpleDateFormat.format(new Date());
		//取得在线的列表
		Object o =getServletContext().getAttribute("list");
		if(o==null) list = null;
		else list = (List<String>)o;
		
		//构造返回的String, json格式
		sb.append("{list:[");
		if(list==null){
			//一个空的数组
			sb.append("],");
		}else{
			for(int i=0;i<list.size();i++){
				sb.append("\"");
				sb.append(list.get(i));
				sb.append("\"");
				//如果是最后一个则不添加 ','
				if(i!=list.size()-1) sb.append(",");
			}
			sb.append("],");
		}
		//把服务器返回的时间添加入json
		sb.append("date:").append("\"").append(text).append("\"");
		sb.append("}");
		
		resp.setCharacterEncoding("UTF-8");
		PrintWriter out = resp.getWriter();
		//停留一秒后,然后再向客户端输出。如果不停留,则浏览器会不停处理,可能崩溃。
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			//
		}
		//返回组装好的json字符串形式
		out.print(sb.toString());
		//Logger.getLogger(this.getClass().getName()).info("服务器段返回json的字符串为:\n"+sb.toString());
	}

}

 

SessionListener

public class SessionListening implements HttpSessionListener {

	@Override
	public void sessionCreated(HttpSessionEvent se) {
	}

	@Override
	public void sessionDestroyed(HttpSessionEvent se) {
		//从session中取得登陆的用户名
		Object o = se.getSession().getAttribute("name");
		//如果未登录则返回
		if(o==null) return;
		String name = (String)o;
		//从ServletContext中获得登陆用户的容器
		Object ob = se.getSession().getServletContext().getAttribute("list");
		//如果容器为null,则返回
		if(ob==null) return;
		List<String> list = (List<String>)ob;
		//从list中移除当前用户
		if(list.contains(name)) list.remove(name);
		//把改变后的list重新放入ServletContext
		se.getSession().getServletContext().setAttribute("list", list);
		Logger.getLogger("session").info("用户"+name+",退出!");
		
	}

}

 

web.xml

  <listener>
  		<listener-class>test.servlet.SessionListening</listener-class>
  </listener>
  
  <servlet>
  		<servlet-name>login</servlet-name>
  		<servlet-class>test.servlet.LoginServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  		<servlet-name>login</servlet-name>
  		<url-pattern>/login</url-pattern>
  </servlet-mapping>
  <servlet>
  		<servlet-name>control</servlet-name>
  		<servlet-class>test.servlet.ControlServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  		<servlet-name>control</servlet-name>
  		<url-pattern>/control</url-pattern>
  </servlet-mapping>

 

虽然设置session的失效时间在5秒,但是总是在大概1分钟的时候调用sessionDestroyed方法。

以上为全部工程文件,

等待高手解答

分享到:
评论
3 楼 paker1989 2014-07-09  
session会在你设置的失效时间的基础上延迟1分钟才会真正失效。
2 楼 酷的飞上天空 2010-07-10  
tonyzzp 写道
我有个疑问
在sessionDestroyed方法里面还可以使用
session.getAttribute()方法吗?
这个时候session是否已经注销掉了呢?。


Notification that a session is about to be invalidated.
此为文档上面对这个方法的说明,此方法被调用时session尚未失效。

现在问题是sessionDestroyed方法,到底都在什么情况下被调用。
我一直向后台发送请求,为什么还会调用此方法
1 楼 tonyzzp 2010-07-08  
我有个疑问
在sessionDestroyed方法里面还可以使用
session.getAttribute()方法吗?
这个时候session是否已经注销掉了呢?。

相关推荐

    session过期时间设置

    在Session失效后,有时需要执行特定操作,例如控制在线用户数量或处理用户多次登录的问题。这时可以利用Servlet API中的监听器(Listener)来实现。监听器是Java Web应用程序中用于监听特定事件(如Session创建和...

    第七次.docx

    * 空闲状态 2 分钟后,HttpSessionListener 中将被调用的方法是 `sessionDestroyed()` (问题 7)。 六、Eclipse 工具开发 Servlet * Eclipse 工具开发 Servlet 会自动将 src 目录下的文件编译成 class 文件存放到 `...

    SessionListener

    3. **会话超时管理**:你可以设置自定义的会话超时策略,比如在`sessionDestroyed()`中检查会话是否因为超时而销毁,如果是因为超时,则记录日志或执行其他操作。 4. **安全控制**:当用户登出时,除了清除Cookie,...

    超星、道有道等面试问题总结.pdf

    这种方式是最简单的实现单例的方式,但是它不考虑线程安全的问题,因此在多线程环境下可能会出现问题。示例如下: ```java public class Singleton { private static Singleton _instance = null; // 私有构造...

    servlet 监听器的实现

    Servlet监听器是Java Web开发中的一个重要概念,它允许开发者在特定事件发生时执行代码,比如在Web应用程序启动、停止时,或者在用户会话创建、销毁时。这为程序员提供了更多的控制权,使得他们能够更好地管理和监控...

    servlet监听器实现踢人小案例

    在`sessionDestroyed`方法中,我们可以检查会话的销毁原因,如果是因为超时或者其他特定条件(如用户请求注销),那么可以执行“踢人”操作,比如清理服务器上的用户信息,更新在线用户列表等。 至于提供的压缩包子...

    Servlet中的八大Listener

    这些Listener提供了在Servlet容器(如Tomcat)管理的生命周期事件上的扩展点,使得我们能够在恰当的时间执行自定义逻辑。 1. **ServletContextListener**: - 当Web应用启动时,容器会调用`contextInitialized()`...

    S2SH用户重复登录问题[文].pdf

    这个问题通常出现在多用户系统中,系统需要确保一个用户在同一时间只能在一个设备或浏览器上保持登录状态,避免数据冲突和安全风险。下面我们将详细介绍如何通过session监听来实现这一功能。 首先,我们需要创建一...

    JavaWeb Session失效时间设置方法

    在Session失效后,有时我们需要执行一些特定的操作,比如: - **控制并发用户数**:当Session失效时,系统中在线用户数会减少,这可以帮助限制系统的负载,保证系统性能在一个合理的范围内。 - **防止同一用户重复...

    用户重复登录问题

    ### 用户重复登录问题详解与解决方案 #### 一、问题背景及需求分析 在现代网络应用中,用户登录安全性和用户体验是非常重要的。一个常见的问题是:如何防止用户在一个客户端登录后,在另一个客户端进行重复登录?...

    设置Session失效的几种方法

    `sessionCreated` 指在Session创建时执行的方法,`sessionDestroyed` 指在Session失效时执行的方法。 例如: ```java public class SessionListener implements HttpSessionListener { public void ...

    监听器.pdf

    在session过期/调用了invalidate方法销毁session时,该监听器方法被执行public void sessionDestroyed(HttpSessionEvent httpSessionEvent)。 3. ServletRequestListener:监听ServletRequest域对象的创建、销毁。...

    servlet学习笔记_监听器.doc

    - 当会话结束(`sessionDestroyed()`),例如会话过期或用户显式调用`invalidate()`方法时,可以用来执行清理操作,如清除缓存数据。 3. **HttpSessionAttributeListener**: - 这个监听器用于监听会话中属性的...

    servlet监听器技术源码

    `requestInitialized`可以在请求开始处理时进行操作,比如记录请求开始时间或添加额外的请求信息。`requestDestroyed`则在请求处理结束时执行,适合清理与请求相关的临时数据。 3. **HttpSessionListener**:针对...

    java统计在线人数

    为了每分钟统计一次在线人数,你可以使用`java.util.Timer`或`ScheduledExecutorService`来定期执行任务。在这个任务中,你可以遍历所有的`HttpSession`,统计有效的会话数量。此外,为了防止数据丢失,可以将统计...

    清华ITjsp课件8

    Web监听允许开发者在特定的Web事件发生时执行自定义代码,例如Servlet上下文、会话或请求的生命周期事件。 首先,我们来看Servlet上下文监听。Servlet上下文(ServletContext)是整个Web应用共享的数据存储区域。...

    判断session过期的方式

    然而,为了安全考虑,Session不会无限期地保持活跃状态,而是设置有一定的过期时间。本篇文章将详细介绍三种判断Session过期的方法。 ### 1. 检查Session有效期 这是最直接的方式,服务器在创建Session时会设置一...

    J2EE 用监听器实现同一用户只能有一个在线.docx

    在J2EE开发中,确保同一用户在同一时间只能有一个在线会话是非常重要的,这涉及到用户身份验证的安全性和系统资源的有效利用。标题提到的"J2EE 用监听器实现同一用户只能有一个在线"是指通过使用Java Servlet API中...

    HttpSessionListener在线人数和历史访问量

    为了长期保存和统计历史访问量,你可能需要定时将内存中的日志数据持久化到数据库,并定期执行统计任务,例如计算过去一天、一周或一月的访问量。 总结,`HttpSessionListener`可以有效地帮助我们跟踪Web应用的在线...

    java web在线人数统计/监听

    每当用户打开一个新的页面或执行一个操作时,服务器都会为该用户创建一个唯一的Session ID,并将其保存在服务器端,同时将ID返回给客户端(通常是存储在Cookie中)。这样,每次客户端发送请求时,都会携带这个...

Global site tag (gtag.js) - Google Analytics