問題:
我們經常會做到的一個功能,將登錄用戶信息保存到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 <!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發送這個對象的字節流,接收方收到流後就可以將流反序列化成對象,然後使用對象的方法和屬性。】
附上測試代碼:session數據丟失測試代碼
OK!!!