你的位置:首页 > Java教程

[Java教程]session没有过期,其保存的数据无故丢失的原因


问题:

我们经常会做到的一个功能,将登录用户信息保存到session中,在页面上显示登录用户名。但是,如果很短时间内甚至几秒没有刷新这个页面的话,这个用户名就消失了,其实就是session中保存的用户数据丢失了。

百度过很多,大部分说是session过期时间设置长一点,或者tomcat的配置问题等等,但都没能解决....在上一篇博客里问到这个问题的时候,有个博友的评论给了我思路,果然O(∩_∩)O哈哈~ 先感谢!!!

然后 看测试过程吧 ↓↓↓

 

下面这个是用户实体类:

 1 package com.lizhou.entity; 2  3 /** 4  * 用户类 5  * @author bojiangzhou 6  * @date 2016年2月28日 7 */ 8 public class User { 9   10   private int id;11   12   private String name;13 14   public User() {15     16   }17 18   public User(int id, String name) {19     this.id = id;20     this.name = name;21   }22 23   public int getId() {24     return id;25   }26 27   public void setId(int id) {28     this.id = id;29   }30 31   public String getName() {32     return name;33   }34 35   public void setName(String name) {36     this.name = name;37   }38   39 }

 

用户servlet:地址栏输入http://localhost:8080/session/UserServlet进行访问,然后会重定向到showUser.jsp (这样刷新页面的时候就不会访问这个servlet了)

 1 package com.lizhou.servlet; 2  3 import java.io.IOException; 4 import javax.servlet.ServletException; 5 import javax.servlet.annotation.WebServlet; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 import com.lizhou.entity.User;11 12 /**13  * 用户servlet14  * @author bojiangzhou15  * @date 2016年2月28日16 */17 public class UserServlet extends HttpServlet {18   private static final long serialVersionUID = 1L;19 20   protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {21     request.setCharacterEncoding("UTF-8");22     23     User user = new User();24     user.setId(1);25     user.setName("Chiangchou");26     27     //将用户信息保存到session中28     request.getSession().setAttribute("user", user);29     //保存一个字符串信息30     request.getSession().setAttribute("message", "用户登录成功");31     32     //重定向33     response.sendRedirect("showUser.jsp");;34     35   }36 37   protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {38     39   }40 41 }

session监听器:监听session的创建与销毁、向session中添加属性、移除属性、更改属性。

 1 package com.lizhou.listener; 2  3 import javax.servlet.http.HttpSessionAttributeListener; 4 import javax.servlet.http.HttpSessionBindingEvent; 5 import javax.servlet.http.HttpSessionEvent; 6 import javax.servlet.http.HttpSessionListener; 7  8 /** 9  * session监听器10  * @author bojiangzhou11  * @date 2016年2月28日12 */13 public class SessionListener implements HttpSessionListener, HttpSessionAttributeListener {14   15   //属性添加时间16   private long addTime;17   18   @Override19   public void sessionCreated(HttpSessionEvent event) {20     System.out.println("session 创建");21   }22 23   @Override24   public void sessionDestroyed(HttpSessionEvent event) {25     System.out.println("session 销毁");26   }27 28   @Override29   public void attributeAdded(HttpSessionBindingEvent event) {30     System.out.println("添加属性:"+event.getName());31     //当属性保存的时候保存当前时间32     addTime = System.currentTimeMillis();33   }34 35   @Override36   public void attributeRemoved(HttpSessionBindingEvent event) {37     System.out.println("移除属性:"+event.getName());38     //当属性移除的时候计算属性保存时间39     long removeTime = System.currentTimeMillis();40     long t = (removeTime-addTime)/1000;41     System.out.println("数据保存时间:"+t+"秒");42   }43 44   @Override45   public void attributeReplaced(HttpSessionBindingEvent event) {46     System.out.println("更改属性:"+event.getName());47   }48 49 }

showUser.jsp 显示用户名

 1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2   pageEncoding="UTF-8"%> 3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 4 <html> 5 <head> 6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 7 <title>显示用户</title> 8 </head> 9 <body>10   用户名:【 ${user.name} 】11   <br/>12   信息:【 ${message} 】13 </body>14 </html>

 

准备工作做好了,下面看测试:

首先直接在地址栏输入地址访问UserServlet,在doGet()里会将用户信息保存到session中,重定向到showUser.jsp时,显示用户名和信息,如图: 可以看到,User对象的属性和字符串都能显示。

 

下面是控制台输出的信息:刚访问servlet后就截图的

 然后,过了一会,控制台如图:

 可以看到,54秒后,user属性移除了,message没有移除,session并没有销毁哦!!!然后刷新页面显示:这就是我们常见到的情况了....

 

然后,百度大部分说设置session过期时间长一点:但是没有效果

1 <!-- 设置session失效时间(单位:分) -->2 <session-config>3  <session-timeout>30</session-timeout>4 </session-config>

然后还有一种方法:在根目录下放一个refresh.jsp文件,内容如下:主要是第6行代码,每隔一秒刷新一下,链接到自己

 1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2   pageEncoding="UTF-8"%> 3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 4 <html> 5 <head> 6 <meta http-equiv="refresh" content="1; url=refresh.jsp"> 7 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 8 <title></title> 9 </head>10 <body>11 12 </body>13 </html>

然后在显示数据的页面(showUser.jsp)加上一句代码:<iframe width=0 height=0 src="refresh.jsp"></iframe>

目的是不断请求服务器,我的理解是服务端以为客户端一直在使用这个对象,就不会移除这个数据了....

这样虽然达到了目的,但有很大的弊端,而且治标不治本:一直请求服务器消耗服务器资源是肯定的了,而且浏览器的刷新图标会一直跳,看着很不爽的...

 

 *****************************************************************************************************************

 最后,看解决办法:只需要将User实现序列化接口Serializable即可,如下:

 1 package com.lizhou.entity; 2  3 import java.io.Serializable; 4  5 /** 6  * 用户类 7  * @author bojiangzhou 8  * @date 2016年2月28日 9 */10 public class User implements Serializable {11   12   private int id;13   14   private String name;15 16   public User() {17     18   }19 20   public User(int id, String name) {21     this.id = id;22     this.name = name;23   }24 25   //getter/setter方法26   27 }

 

将要保存到session中的对象实现序列化接口Serializable,这样用户数据就一直保存在session里了,不管你怎么刷新,除非session销毁,数据一直都在!!!

那么原因是什么呢?下面是我百度的一段:

【Object serialization 允许你将实现了Serializable接口的对象转换为字节序列,这些字节序列可以被完全存储以备以后重新生成原来的对象。
举个例子:网络传输的时候,可以传字符串,亦可以传对象object,例如socket。传字符串的时候接收方很容易解析出来,但是,传一个对象的时候,对方读完字节流后,不知道你传的什么对象,所以没办法给转成原来的对象并解析对象的属性,这时候就要用到序列化和反序列化。类实现序列化接口,socket发送这个对象的字节流,接收方收到流后就可以将流反序列化成对象,然后使用对象的方法和属性。】

 

 OK!!!