问题:

我们经常会做到的一个功能,将登录用户信息保存到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 * 用户servlet
 14 * @author bojiangzhou
 15 * @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 bojiangzhou
 11 * @date 2016年2月28日
 12 */
 13 public class SessionListener implements HttpSessionListener, HttpSessionAttributeListener {
 14
 15 //属性添加时间
 16 private long addTime;
 17
 18 @Override
 19 public void sessionCreated(HttpSessionEvent event) {
 20 System.out.println(“session 创建”);
 21 }
 22
 23 @Override
 24 public void sessionDestroyed(HttpSessionEvent event) {
 25 System.out.println(“session 销毁”);
 26 }
 27
 28 @Override
 29 public void attributeAdded(HttpSessionBindingEvent event) {
 30 System.out.println(“添加属性:”+event.getName());
 31 //当属性保存的时候保存当前时间
 32 addTime = System.currentTimeMillis();
 33 }
 34
 35 @Override
 36 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 @Override
 45 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 
 4 
 5 
 6 
 7 显示用户
 8 
 9 
 10 用户名:【 ${user.name} 】
 11 
 12 信息:【 ${message} 】
 13 
 14

复制代码

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

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

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

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

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

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

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

复制代码

1 <%@ page language=“java” contentType=“text/html; charset=UTF-8”
 2 pageEncoding=“UTF-8”%>
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11
 12 
 13

复制代码

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

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

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


最后,看解决办法:只需要将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发送这个对象的字节流,接收方收到流后就可以将流反序列化成对象,然后使用对象的方法和属性。】