在做 Web Application 時,因為 Web Project 有 session 自動失效的問題,所以如何讓用戶登錄一次系統就能長時間運行三個月,就是個問題。
后來,看到 session 失效的攔截器代碼,就猜想能否通過攔截器來實現。
查資料發現可行:用戶登錄時將帳號密碼存入cookie,cookie可以存儲1年至更久,當session失效被攔截時,在攔截器內讀取cookie 中的用戶名和密碼后再登錄。(登錄過程隱藏對用戶不可見)。
在實踐過程中遇到個問題: 在攔截器內重新實現登錄過程(包括寫session),此時寫session是成功的,但是返回被攔截器攔截的 Action 方法內時,Action 內的方法讀取的session卻是空的。(2017-06-12 更新,出錯原因是保存的sesion和讀取的session分別是Strut2包裝的session和JSP/Sevlert內置的session,導致讀取為空,參見)
方法一:設置 session-timeout 參數值
最簡單的辦法是,在Java Web 中可通過設置 web.xml 中的 session-timeout 為 -1 即可實現 session 永不失效。
Java Web中有關 Session 失效的設置有三處:
1. 頁面或者代碼內通過 session.setMaxInactiveInterval
2. 項目的web.xml 中的 session-timeout (驗證有效)
3. Tomcat 的 server.xml 中的 (該方法本文未驗證,網上搜集)
<Context path="/livsorder" docBase="/home/httpd/html/livsorder" defaultSessionTimeOut="3600" isWARExpanded="true" isWARValidated="false" isInvokerEnabled="true" isWorkDirPersistent="false"/>
4. Tomcat 的 web.xml 中的 (該方法本文未驗證,網上搜集)
<session-config> <session-timeout>30</session-timeout> </session-config>
分別對應:
1. 當前會話生效
2. 整個Web應用有效
3. 不詳
4. 不詳
設置產生效果的優先順序很顯然是:1 -> 2 ,沒有指明就是用默認設置。
另外: setMaxInactiveInterval的參數是秒,session-config當中配置的session-timeout是分鍾。 設置session-timeout是永久有效。【setMaxInactiveInterval(-1)也是元永久有效(本人未測試)】。測試是否是永久有效很簡單,只需要在本地測試(localhost)時,將本機的時間調整為幾個月之后即可。
但在實際使用中並不理想,因為超出 tomcat 的默認是 30 分鍾,如果修改 tomcat 默認值,會影響其他項目不說,也很容易遺忘,對今后產生莫名其妙的問題。
方法二:使用 Struts2 攔截器
原理:在使用了 Struts 框架的代碼中,使用攔截器,測試Session 是否為空,若是空,利用 cookie 里藏的用戶名和密碼進行登錄,並保存到 session 中。
代碼:(本人親測,實際使用)
1. 登錄保存到 Struts2 包裝的 session中(注意,前后session要對應)
根據項目需要,可決定是否加密。我示例未加密。
// 你的登錄方法內部 // user 是登錄成功后的用戶對象 ActionContext.getContext().getSession().put("user", user); //創建或覆蓋COOKIE Cookie ckName = new Cookie("jsjgUserName", username); Cookie ckPwd = new Cookie("jsjgUserPwd", password); ckName.setMaxAge(365*24*60*60); ckPwd.setMaxAge(365*24*60*60); response.addCookie(ckName); response.addCookie(ckPwd);
2. 攔截器代碼
package com.tools; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.http.Cookie; import javax.servlet.http.HttpSession; import org.apache.struts2.ServletActionContext; import org.apache.struts2.StrutsStatics; import org.springframework.context.ApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; import com.zhzx.class_entity.User; import com.zhzx.service.UserService; @SuppressWarnings("serial") public class MyInterceptor implements Interceptor { public void destroy() { } public void init() { } public String intercept(ActionInvocation actionInvocation) throws Exception { // 確認Session是否過期 Map strutSession = actionInvocation.getInvocationContext().getSession(); Cookie[] cookies = ServletActionContext.getRequest().getCookies(); User us=(User) strutSession.get("user"); String userName = ""; String userPwd = ""; if (us!=null&&!"".equals(us)) { return actionInvocation.invoke(); } else { //從cookie得到登錄賬戶 if(cookies != null){ for(Cookie cookie:cookies){ if(cookie.getName().equalsIgnoreCase("jsjgUserName")){ userName = cookie.getValue(); System.out.println(userName); }else if(cookie.getName().equalsIgnoreCase("jsjgUserPwd")){ userPwd = cookie.getValue(); } } //登錄 if(userName != null && userPwd != null){ //因項目使用了SSH,所以這里是獲取Spring管理的bean ServletContext context = (ServletContext) actionInvocation.getInvocationContext().get(StrutsStatics.SERVLET_CONTEXT); ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(context); UserService userService = (UserService)ctx.getBean("UserService"); //是否注入成功 System.out.println(userService); //登錄並放入Strtu2包裝的session User user=userService.Login(userName); if(user != null && user.getPassword().toLowerCase().equals(userPwd.toLowerCase())){ strutSession.put("user", user); } return actionInvocation.invoke(); } } return "timeout"; } } }
然后攔截器按照常規方法使用即可。攔截器可以看看 Struts in Action ,Struts實戰之類的書及PDF,有詳細的講解和例子。
吐槽:Java是太龐雜了,框架多不說,使用起來也方法各樣,一會兒流行配置文件,一會兒流行注解,一會SSH,一會SSM,一會Sping MVC。
我就想說這不都是自己折騰自己么,學習成本不是成本么,發明出這么多輪子,軟件行業不還是加班。舊的軟件項目不還是要維護。
Java體系真是自己折騰自己,真心無愛了。
我覺得框架只是工具,就像武俠世界里,真正的高手是用什么工具都可以殺人於無形,那管你是用很多人鄙視的 ASP.NET 還是自以為很牛逼的Java Web,
甲方和老板關心的無非是你做完了么,做的好看么,是不是?
程序員,工程師們還是消停點好,多關心下自己的健康和身邊的人不好么?