先敘述一下 session 的實現原理吧!
session 服務器爲每個客戶端訪問開闢的一塊內存區域,可以存放一些客戶端的一些操作信息
正常情況下在用戶通過客戶端訪問服務器這個過程中 session 一直存活,直到客戶端關閉,服務器中的 session 被銷燬
非正常情況下,服務器調用 session.invalidate() 方法進行手動銷燬
session 依賴於 cookie !!!
沒有 cookie 是無法通過 request.getSession() 獲取對應的客戶端的 session 的
具體實現原理
客戶端第一次訪問服務器,服務器返回
在服務器返回的響應頭中,可以看到 Set-Cookie 字段,這個字段中,JSESSION=94E09A118319882388C08A27A42696DB
94E09A118319882388C08A27A42696DB 爲服務器保存的 session 對應的 ID
當客戶端再訪問該網站的其他鏈接 👇
服務器的響應頭則不會再有 Set-Cookie 字段了👆
但是再看客戶端的請求頭 👇
會自動的將 JSESSIONID 這個 Cookie 帶上 👆,服務器根據該字段對應的值就可以拿到該客戶端保存在服務器的 session 對象
此時可以通過 request.getSession() 獲得對應的 session 對象
然而這都是基於客戶端沒有禁止 Cookie 的情況下,當客戶端禁止了 Cookie ,當訪問服務器的其他鏈接,將不會攜帶 Cookie 了,此時又該怎麼辦呢?(*^_^*)
解決辦法之一:將 jsessionid 這個保存在客戶端的值拼接在對應的 url 上,這樣服務器可以通過解析 url 將 jsessionid 對應的值取出來,然後通過這個 sessionId 去獲取保存在服務器中的 session 實例對象
通過 HttpServletResponse response,response.encodeURL() 方法進行將對應的 jsessionid 拼進去
現在說一下 response.encodeURL() 該函數的作用吧
首先判斷客戶端是否禁止了 Cookie ,如果沒有禁止,則返回 request.getRequestURI() 這個的值不會拼接上 jsessionid
如果判斷客戶端禁止了 Cookie, 則會在 request.getContextPath()+"/hello/index" 後拼接上 jsessionid=xxx 👇
當再訪問服務器時,鏈接上拼上了 jsessionid 值 👇
客戶端禁止了 Cookie ,所以請求頭中 Cookie 值並沒有帶上 👆
然後就可以通過服務器解析對應的 url 獲取 jsessionid 獲取對應的 sessionId, 然後根據 sessionId 查詢服務器對應的 session 實例對象 👇
基本的原理已經講的差不多了,現在給出一個基於 SpringBoot 的一個解決方案,獲取 session 的
MySessionContext 代碼
package mr.s.javaee.context;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
public class MySessionContext {
private static MySessionContext instance;
private HashMap<String,HttpSession> sessionMap;
private MySessionContext() {
sessionMap = new HashMap<String,HttpSession>();
}
public static MySessionContext getInstance() {
if (instance == null) {
instance = new MySessionContext();
}
return instance;
}
public synchronized void addSession(HttpSession session) {
if (session != null) {
sessionMap.put(session.getId(), session);
}
}
public synchronized void delSession(HttpSession session) {
if (session != null) {
sessionMap.remove(session.getId());
}
}
public synchronized HttpSession getSession(String sessionID) {
if (sessionID == null) {
return null;
}
return sessionMap.get(sessionID);
}
}
SessionListener 代碼
package mr.s.javaee.listener;
import mr.s.javaee.context.MySessionContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener
public class SessionListener implements HttpSessionListener {
private MySessionContext myc = MySessionContext.getInstance();
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
HttpSession session = httpSessionEvent.getSession();
myc.addSession(session);
}
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
HttpSession session = httpSessionEvent.getSession();
myc.delSession(session);
}
}
最後需要修改一下,啓動類!加上 @ServletComponentScan 註解 👇
具體獲得 session 的核心代碼
String uri = request.getRequestURI();
String sessionId = uri.split("jsessionid=")[1];
System.out.println(sessionId);
MySessionContext myc= MySessionContext.getInstance();
HttpSession session = myc.getSession(sessionId);
String name = session.getAttribute("name").toString();