一. 會話
1. 什麼是會話?
(1) 會話可簡單理解爲:用戶開一個瀏覽器,點擊多個超鏈接,訪問服務器多個web資源,然後關閉瀏覽器,整個
過程稱之爲一個會話。
(2) 一次會話:打開瀏覽器 -> 訪問一些服務器內容 -> 關閉瀏覽器
2. 會話過程中要解決的一些問題
每個用戶在使用瀏覽器與服務器進行會話的過程中,不可避免各自會產生一些數據,服務器要想辦法爲每個用戶
保存這些數據。
(1) 模擬登陸場景
① 過程:打開瀏覽器 -> 瀏覽到登陸頁面 -> 輸入用戶名和密碼 -> 訪問到用戶主頁(顯示用戶名)
修改密碼(輸入原密碼)
修改收貨地址
.......
②存在的問題:在此處登錄會話過程中產生的數據(用戶會話數據)如何保存下來呢?
(2) 模擬購物場景
①過程:
打開瀏覽器 -> 瀏覽商品列表 -> 加入購物車(把商品信息保存下來) -> 關閉瀏覽器
打開瀏覽器 -> 直接進入購物車 -> 查看到上次加入購物車的商品 -> 下訂單 -> 支付
②存在的問題:在購物會話過程中,如何保存商品信息?
3. 會話管理:
會話管理就是管理瀏覽器客戶端和服務器端之間會話過程中產生的會話數據。
4. 保存會話數據的兩種技術:
(1) Cookie技術:會話數據保存在瀏覽器客戶端。
(2) Session技術:會話數據保存在服務器端。
二. Cookie技術
1. 什麼是Cookie技術?
Cookie是客戶端技術,服務器把每個用戶的數據以cookie的形式寫給用戶各自的瀏覽器。當用戶使用瀏覽器再去
訪問服務器中的web資源時,就會帶着各自的數據去。這樣,web資源處理的就是用戶各自的數據了。
2. Cookie技術核心
Cookie類:用於存儲會話數據。代碼要在服務器端完成,服務器是運行這些代碼的,我們在服務器只是把cookie
創建出來,但是服務器並不保存數據,而是把cookie數據發送到瀏覽器端去保存。而代碼要交給服務器運行,那
麼這個代碼可以寫到Servlet中去,Servlet可以通過瀏覽器訪問運行。
javax.servlet.http.Cookie類用於創建一個Cookie,response接口也中定義了一個addCookie方法,它用於在其
響應頭中增加一個相應的Set-Cookie頭字段。 同樣,request接口中也定義了一個getCookies方法,它用於獲取
客戶端提交的Cookie。
(1) 構造Cookie對象
Cookie(java.lang.String name, java.lang.String value); ----我們需要通過名字來獲取對應的值。
(2) 設置cookie
① void setPath(java.lang.String uri); ----設置cookie的有效訪問路徑
② void setMaxAge(int expiry); ----設置cookie的有效時間
③ void setValue(java.lang.String newValue); ----設置cookie的值
(3) 發送cookie到瀏覽器端保存
void response.addCookie(Cookie cookie); ----發送cookie
(4) 瀏覽器是可以把cookie再發送回來的,服務器接收cookie
Cookie[] request.getCookies(); ----接收cookie
3. Cookie原理
(1) 服務器創建cookie對象,把會話數據存儲到cookie對象中。
new Cookie("name","value");
(2) 服務器發送cookie信息到瀏覽器
response.addCookie(cookie);
舉例: set-cookie: name=eric (隱藏發送了一個set-cookie名稱的響應頭)
(3) 瀏覽器得到服務器發送的cookie,然後保存在瀏覽器端。
(4) 瀏覽器在下次訪問服務器時,會帶着cookie信息
舉例:cookie: name=eric (隱藏帶着一個叫cookie名稱的請求頭)
(5) 服務器接收到瀏覽器帶來的cookie信息
request.getCookies();
4. Cookie的細節
(1) void setPath(java.lang.String uri):設置cookie的有效訪問路徑。有效路徑指的是cookie的有效路徑保存在
哪裏,那麼瀏覽器在有效路徑下訪問服務器時就會帶着cookie信息,否則不帶cookie信息。
(2) void setMaxAge(int expiry):設置cookie的有效時間。
① 正整數:表示cookie數據保存瀏覽器的緩存目錄(硬盤中),數值表示保存的時間。
② 負整數:表示cookie數據保存瀏覽器的內存中。瀏覽器關閉cookie就丟失了!!
③ 零:表示刪除同名的cookie數據。
(3) 一個Cookie只能標識一種信息,它至少含有一個標識該信息的名稱(NAME)和設置值(VALUE)。
(4) 一個WEB站點可以給一個WEB瀏覽器發送多個Cookie,一個WEB瀏覽器也可以存儲多個WEB站點提供的
Cookie。
(5) 如果創建了一個cookie,並將它發送到瀏覽器,默認情況下它是一個會話級別的cookie(即存儲在瀏覽器的
內存中),用戶退出瀏覽器之後即被刪除。若希望瀏覽器將該cookie存儲在磁盤上,則需要使用maxAge,並給
出一個以秒爲單位的時間。將最大時效設爲0則是命令瀏覽器刪除該cookie。
(6) 注意,刪除cookie時,path必須一致,否則不會刪除。
(7) Cookie數據類型只能保存非中文字符串類型的。可以保存多個cookie,但是瀏覽器一般只允許存放300個
Cookie,每個站點最多存放20個Cookie,每個Cookie的大小限制爲4KB。
5. Cookie的實例
(1) 實例一:發送與接收Cookie
@WebServlet("/CookieDemo1")
public class CookieDemo1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.創建Cookie對象
Cookie cookie = new Cookie("name", "value");
Cookie cookie1 = new Cookie("email", "[email protected]");
// 2.把cookie數據發送到瀏覽器(cookie數據也需要通過響應才能發送出去)
// 但是cookie數據要跟在響應的哪一部分呢?可以通過響應頭(set-cookie名稱)發送。
// response.setHeader("set-cookie",cookie.getName()+"="+cookie.getValue());
// 推薦使用這種方式,可以避免手動發送cookie信息
response.addCookie(cookie);
response.addCookie(cookie1);
// 3.接收瀏覽器發送的cookie信息
/*
* String name = request.getHeader("cookie"); System.out.println(name);
*/
Cookie[] cookies = request.getCookies();
// 注意:要判斷是否爲空,如果不判斷,可能空指針
if (cookies != null) {
// 遍歷
for (Cookie c : cookies) {
String name = c.getName();
String value = c.getValue();
System.out.println(name + "=" + value);
}
} else {
System.out.println("沒有接收到cookie數據");
}
}
}
運行結果如下圖所示:
(2) 實例二:設置Cookie的有效路徑
@WebServlet("/CookieDemo2")
public class CookieDemo2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.創建Cookie對象
Cookie cookie = new Cookie("name", "eric");
Cookie cookie1 = new Cookie("email", "[email protected]");
/*
* (1)設置cookie的有效路徑,默認情況下,有效路徑在當前web應用下/day11
*/
cookie.setPath("/day11");
cookie1.setPath("/day12");
// 2.把cookie數據發送到瀏覽器(cookie數據也需要通過響應才能發送出去)
// 但是cookie數據要跟在響應的哪一部分呢?可以通過響應頭(set-cookie名稱)發送。
// response.setHeader("set-cookie",
// cookie.getName()+"="+cookie.getValue());
// 推薦使用這種方式,可以避免手動發送cookie信息
response.addCookie(cookie);
response.addCookie(cookie1);
// 3.接收瀏覽器發送的cookie信息
/*
* String name = request.getHeader("cookie"); System.out.println(name);
*/
Cookie[] cookies = request.getCookies();
// 注意:要判斷是否爲空,如果不判斷,可能空指針
if (cookies != null) {
// 遍歷
for (Cookie c : cookies) {
String name = c.getName();
String value = c.getValue();
System.out.println(name + "=" + value);
}
} else {
System.out.println("沒有接收到cookie數據");
}
}
}
(3) 實例三:設置Cookie的有效時間
/*
* 設置Cookie的有效時間
*/
@WebServlet("/CookieDemo3")
public class CookieDemo3 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.創建Cookie對象
Cookie cookie = new Cookie("name", "eric");
/*
* (2) 設置Cookie的有效時間
*/
//cookie.setMaxAge(20);//20秒,意味着Cookie是20秒之後過期。從最後不調用Cookie開始計算。
cookie.setMaxAge(-1);//cookie會保存在瀏覽器內存(會話Cookie)。
// 2.把cookie數據發送到瀏覽器(cookie數據也需要通過響應才能發送出去)
// 但是cookie數據要跟在響應的哪一部分呢?可以通過響應頭(set-cookie名稱)發送。
// response.setHeader("set-cookie",
// cookie.getName()+"="+cookie.getValue());
// 推薦使用這種方式,可以避免手動發送cookie信息
response.addCookie(cookie);
// 3.接收瀏覽器發送的cookie信息
/*
* String name = request.getHeader("cookie"); System.out.println(name);
*/
Cookie[] cookies = request.getCookies();
// 注意:要判斷是否爲空,如果不判斷,可能空指針
if (cookies != null) {
// 遍歷
for (Cookie c : cookies) {
String name = c.getName();
String value = c.getValue();
System.out.println(name + "=" + value);
}
} else {
System.out.println("沒有接收到cookie數據");
}
}
}
(4) 實例四:刪除Cookie
@WebServlet("/DeleteCookie")
public class DeleteCookie extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Cookie cookie = new Cookie("name", "xxx");
cookie.setMaxAge(0);// 刪除同名的Cookie
response.addCookie(cookie);
System.out.println("刪除成功");
}
}
三. Session技術
1. 引入
(1) Cookie的侷限:
① Cookie只能存字符串類型,不能保存對象;
② 只能存非中文的數據;
③ 1個Cookie的容量不超過4KB;
(2) 注意:Cookie是保存在瀏覽器(客戶端)中,所以它是可以被瀏覽器清除的。如果要保存非字符串,超過4kb內
容,只能使用session技術!!
2. 什麼是Session技術?
(1) Session是服務器端技術,利用這個技術,服務器在運行時可以爲每一個用戶的瀏覽器創建一個其獨享的
session對象,由於session爲用戶瀏覽器獨享,所以用戶在訪問服務器的web資源時,可以把各自的數據放在各
自的session中,當用戶再去訪問服務器中的其它web資源時,其它web資源再從用戶各自的session中取出數據
爲用戶服務。
(2) 在WEB開發中,服務器可以爲每個用戶瀏覽器創建一個會話對象(session對象),注意:一個瀏覽器獨佔一
個session對象(默認情況下)。因此,在需要保存用戶數據時,服務器程序可以把用戶數據寫到用戶瀏覽器獨佔的
session中,當用戶使用瀏覽器訪問其它程序時,其它程序可以從用戶的session中取出該用戶的數據,爲用戶服
務。
(3) Session對象由服務器創建,開發人員可以調用request對象的getSession方法得到session對象。
3. Session和Cookie的主要區別
(1) Cookie是把用戶的數據寫給用戶的瀏覽器。
(2)Session技術把用戶的數據寫到用戶獨佔的session中。
4. Session技術核心
HttpSession類:用於保存會話數據。
(1) 創建或得到session對象
① HttpSession getSession()
② HttpSession getSession(boolean create)
(2) 設置session對象
① void setMaxInactiveInterval(int interval):設置session的有效時間
② void invalidate():銷燬session對象
③ java.lang.String getId():得到session編號
(3) 保存會話數據到session對象
① void setAttribute(java.lang.String name, java.lang.Object value):保存數據
② java.lang.Object getAttribute(java.lang.String name):獲取數據
③ void removeAttribute(java.lang.String name):清除數據
5. Session原理
注意:雖然代碼相同,但是不同的瀏覽器得到的都是各自的數據。
(1) 問題:
在每一種情況下它得到的對象可能不一樣,但是代碼是一模一樣的,卻可以拿出不一樣的對象,爲什麼會出現這
種情況?服務器怎麼能夠識別不同的瀏覽者?
(2) 注意:
在域對象中保存了數據,要想再把這個數據取出來,取決於是否是同一個對象。它的前提是在哪個session域對象
保存數據,就必須從哪個域對象取出!
(3) 分析:
可能是瀏覽器發了一個標記,每創建一個session對象,就會給session對象s1分配一個唯一的標記,這個標記在
執行完代碼後會返回給瀏覽器。再用新窗口訪問時,是帶着s001的這個標記去服務器查詢的,在服務器中找到與
它對應的s1對象。
① 瀏覽器1:(給s1分配一個唯一的標記:s001,把s001發送給瀏覽器)
創建session對象,保存會話數據
HttpSession session = request.getSession(); --保存會話數據 s1
② 瀏覽器1的新窗口:(帶着s001的標記到服務器查詢,s001->s1,返回s1)
得到session對象的會話數據
HttpSession session = request.getSession(); --可以取出 s1
③ 新的瀏覽器1:(沒有帶s001,不能返回s1)
得到session對象的會話數據
HttpSession session = request.getSession(); --不可以取出 s2
④ 瀏覽器2:(沒有帶s001,不能返回s1)
得到session對象的會話數據
HttpSession session = request.getSession(); --不可以取出 s3
6. 代碼解讀(僞代碼)
HttpSession session = request.getSession();
(1) 第一次訪問創建session對象,給session對象分配一個唯一的ID,是JSESSIONID;
new HttpSession();
(2) 把JSESSIONID作爲Cookie的值發送給瀏覽器保存;
Cookie cookie = new Cookie("JSESSIONID", sessionID);
response.addCookie(cookie);
(3) 第二次訪問的時候,瀏覽器帶着JSESSIONID的cookie訪問服務器;
(4) 服務器得到JSESSIONID,在服務器的內存中搜索是否存在對應編號的session對象;
if(找到){
return map.get(sessionID);
}
Map<String,HttpSession>
<"s001", s1>
<"s001",s2>
(5) 如果找到對應編號的session對象,直接返回該對象;
(6) 如果找不到對應編號的session對象,創建新的session對象,繼續走1的流程;
結論:通過JSESSION的cookie值在服務器找session對象!
7. Session細節
(1) java.lang.String getId():得到session編號;
(2) 兩個getSession方法:
其中帶參數的裏面是一個布爾值,Session session = getSession(boolean flag);
① getSession(true) / getSession():創建或得到session對象。如果沒有匹配的session編號,自動創
建新的session對象。
② getSession(false):得到session對象。如果沒有匹配的session編號,返回null。
(3) void setMaxInactiveInterval(int interval) : 設置session的有效時間。
注意:關閉瀏覽器後session對象是沒有銷燬的,關了瀏覽器不可能會影響到服務器,session是保存在服務器端
的。
(4) session對象銷燬時間:
① 默認情況30分鐘後服務器自動回收;
② 修改session回收時間;
③ 全局修改session有效時間;
④ 手動銷燬session對象;
void invalidate():銷燬session對象。
(5) 如何避免瀏覽器的JSESSIONID的cookie隨着瀏覽器關閉而丟失的問題?
8. Session實例
(1) 實例一:保存會話數據到Session域對象和從Session域對象中取出會話數據。
/*
* 保存會話數據到session域對象
*/
@WebServlet("/SessionDemo1")
public class SessionDemo1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.創建session對象
HttpSession session = request.getSession();
// 2.保存會話數據
session.setAttribute("name", "rose");
System.out.println("保存成功");
}
}
/*
* 從session域對象中取出會話數據。
*/
@WebServlet("/SessionDemo2")
public class SessionDemo2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.得到session對象
HttpSession session = request.getSession();
// 2.取出數據
String name = (String) session.getAttribute("name");
System.out.println("name=" + name);
}
}
運行結果如下圖所示:
從結果中可以看出,如果我們先訪問SessionDemo2,取出的數據是name=null,因爲我們還沒有存數據,只有
先訪問SessionDemo1後把數據存入Session對象中,那麼才能取出數據。
(2) 實例二:避免cookie隨着瀏覽器的關閉而丟失。
@WebServlet("/SessionDemo3")
public class SessionDemo3 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.創建session對象
HttpSession session = request.getSession();
/*
* 得到session編號
*/
System.out.println("id=" + session.getId());
// 2.保存會話數據
session.setAttribute("name", "rose");
/*
* 手動發送一個硬盤保存的cookie數據給瀏覽器,這樣就可以避免cookie隨着瀏覽器的關閉而丟失的問題。
*/
Cookie c = new Cookie("JSESSIONID", session.getId());
c.setMaxAge(60 * 60);
response.addCookie(c);
}
}
@WebServlet("/SessionDemo4")
public class SessionDemo4 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.得到session對象
HttpSession session = request.getSession();
/*
* 得到session編號
*/
System.out.println("id=" + session.getId());
// 2.取出數據
String name = (String) session.getAttribute("name");
System.out.println("name=" + name);
}
}
運行結果如下圖所示:
通過運行結果可以發現:當我們關閉瀏覽器,再訪問SessionDemo4的時候仍然可以取出數據。
(3) 實例三:銷燬Session對象。
/*
* 銷燬session對象
*/
@WebServlet("/DeleteSession")
public class DeleteSession extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession(false);// 如果裏面傳入false,那麼必須判定它不爲空
if (session != null) {
session.invalidate();// 手動銷燬
}
System.out.println("銷燬成功");
}
}