注冊用戶即可下載全站資源 關注Java幫幫微信公眾號
 

Web-第十天 Cookie&Session學習【悟空教程】

128
發表時間:2018-11-07 16:57來源:Java幫幫-微信公眾號


Cookie&Session會話技術

今日內容介紹

  • 案例一:記錄用戶的上次訪問時間

  • 案例二:一次性驗證碼

今日內容學習目標

  • 可以響應給瀏覽器Cookie信息

  • 可以接收瀏覽器攜帶的cookie信息

  • 理解cookie的執行原理

  • 可以對session作用域的數據進行操作:存放、獲得、移除

  • 理解session的執行原理

第1章 案例:記錄用戶的上次訪問的時間:

1.1 需求:

當用戶訪問某些Web應用時,經常會顯示出該用戶上一次的訪問時間。例如,QQ登錄成功后,會顯示用戶上次的登錄時間。通過本任務,讀者將學會如何使用Cookie技術實現顯示用戶上次的訪問時間的功能。

1.2 相關知識點

1.2.1 會話的概述:

1.2.1.1 什么是會話

在日常生活中,從撥通電話到掛斷電話之間的一連串的你問我答的過程就是一個會話。Web應用中的會話過程類似于生活中的打電話過程,它指的是一個客戶端(瀏覽器)與Web服務器之間連續發生的一系列請求和響應過程,例如,一個用戶在某網站上的整個購物過程就是一個會話。

在打電話過程中,通話雙方會有通話內容,同樣,在客戶端與服務器端交互的過程中,也會產生一些數據。例如,用戶甲和乙分別登錄了購物網站,甲購買了一個Nokia手機,乙購買了一個Ipad,當這兩個用戶結賬時,Web服務器需要對用戶甲和乙的信息分別進行保存。在前面章節講解的對象中,HttpServletRequest對象和ServletContext對象都可以對數據進行保存,但是這兩個對象都不可行,具體原因如下:


1)客戶端請求Web服務器時,針對每次HTTP請求,Web服務器都會創建一個HttpServletRequest對象,該對象只能保存本次請求所傳遞的數據。由于購買和結賬是兩個不同的請求,因此,在發送結賬請求時,之前購買請求中的數據將會丟失。


2)使用ServletContext對象保存數據時,由于同一個Web應用共享的是同一個ServletContext對象,因此,當用戶在發送結賬請求時,由于無法區分哪些商品是哪個用戶所購買的,而會將該購物網站中所有用戶購買的商品進行結算,這顯然也是不可行的。


3)為了保存會話過程中產生的數據,在Servlet技術中,提供了兩個用于保存會話數據的對象,分別是CookieSession。關于CookieSession的相關知識,將在下面的小節進行詳細講解。

  • Cookie  和瀏覽器緩存有什么區別?

共同點:瀏覽器緩存可以緩存任意內容(上網瀏覽的所有內容)、cookie只是服務器需要瀏覽器緩存數據(瀏覽器緩存中一部分)


1.2.1.2 什么是Cookie

在現實生活中,當顧客在購物時,商城經常會贈送顧客一張會員卡,卡上記錄用戶的個人信息(姓名,手機號等)、消費額度和積分額度等。顧客一旦接受了會員卡,以后每次光臨該商場時,都可以使用這張會員卡,商場也將根據會員卡上的消費記錄計算會員的優惠額度和累加積分。

Web應用中,Cookie的功能類似于這張會員卡,當用戶通過瀏覽器訪問Web服務器時,服務器會給客戶端發送一些信息,這些信息都保存在Cookie中。這樣,當該瀏覽器再次訪問服務器時,都會在請求頭中將Cookie發送給服務器,方便服務器對瀏覽器做出正確的響應。

服務器向客戶端發送Cookie時,會在HTTP響應頭字段中增加Set-Cookie響應頭字段。Set-Cookie頭字段中設置的Cookie遵循一定的語法格式,具體示例如下:

Set-Cookie: user=javahelp; Path=/;

在上述示例中,user表示Cookie的名稱,javahelp表示Cookie的值,Path表示Cookie的屬性。需要注意的是,Cookie必須以鍵值對的形式存在,其屬性可以有多個,但這些屬性之間必須用分號;和空格分隔。

了解了Cookie信息的發送方式后,接下來,通過一張圖來描述Cookie在瀏覽器和服務器之間的傳輸過程,具體如圖5-1所示。

圖5-1Cookie在瀏覽器和服務器之間傳輸的過程

在圖5-1中,描述了Cookie在瀏覽器和服務器之間的傳輸過程。當用戶第一次訪問服務器時,服務器會在響應消息中增加Set-Cookie頭字段,將用戶信息以Cookie的形式發送給瀏覽器。一旦用戶瀏覽器接受了服務器發送的Cookie信息,就會將它保存在瀏覽器的緩沖區中,這樣,當瀏覽器后續訪問該服務器時,都會在請求消息中將用戶信息以Cookie的形式發送給Web服務器,從而使服務器端分辨出當前請求是由哪個用戶發出的。


1.2.1.3 Cookie的基本使用

Cookie將用戶的信息保存到客戶端瀏覽器的一個技術,當下次訪問的時候,瀏覽器會自動攜帶Cookie的信息過來到服務器端.

  • Cookie的基本使用:

創建cookie

new Cookie(name,value) javax.servlet.http.Cookie

cookie發送給瀏覽器:

HttpServletResponse.addCookie(javax.servlet.http.Cookie)

接收瀏覽器攜帶的所有cookie

HttpServletRequest.getCookies()

1.3 案例分析

1.3.1 流程分析

1.3.2 步驟分析

第一步.獲得從客戶端帶過來的所有的Cookie:

第二步.從所有的Cookie中查找指定名稱的Cookie:

第三步.判斷是否是第一次訪問:

* 是第一次:顯示歡迎

* 不是第一次:顯示歡迎 同時顯示上次訪問時間.

第四步.記錄當前的時間,并且利用Cookie將時間回寫到瀏覽器端.  


1.4 代碼實現

public class VisitServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

/**

* 1.獲得從客戶端帶過來的所有的Cookie:

* 2.從所有的Cookie中查找指定名稱的Cookie

* 3.判斷是否是第一次訪問:

*   * 是第一次:顯示歡迎

*   * 不是第一次:顯示歡迎 同時顯示上次訪問時間.

* 4.記錄當前的時間,并且利用Cookie將時間回寫到瀏覽器端.

*/

// 獲得客戶端的所有的Cookie:

Cookie[] cookies = request.getCookies();

// cookies的數組中查找指定名稱的Cookie:

Cookie cookie = CookieUtils.findCookie(cookies, "visitTime");

// 判斷是否是第一次訪問:

response.setContentType("text/html;charset=UTF-8");

if(cookie == null){

// 第一次訪問

response.getWriter().println("<h1>歡迎來到本網站!</h1>");

}else{

// 不是第一次

long time = Long.parseLong(cookie.getValue());

Date date = new Date(time);

response.getWriter().println("<h1>歡迎來到本網站!您的上次訪問時間是:"+date.toLocaleString()+"</h1>");

}

// 記錄當前的時間,回寫到Cookie.

Cookie c = new Cookie("visitTime",""+System.currentTimeMillis());

response.addCookie(c);

}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doGet(request, response);

}

}


1.5 總結:

1.5.1 Cookie的分類

  • 會話級別的Cookie:默認的.關閉了瀏覽器Cookie就銷毀了.

  • 持久級別的Cookie:需要設置有效時長的.關閉瀏覽器也不會銷毀的Cookie.

    • setMaxAge(int expiry);  以秒為單位的時間,超過了該時間后Cookie會自動銷毀. setMaxAge(0),手動刪除持久性的Cookie。(前提:path和name必須一致)

    • setPath(String uri); 設置Cookie的有效路徑.

  • 例如:

       1)cookie.setPath("/day16/demo");

       表示day16 項目下,【demo目錄】下所有的servlet,

        都可以訪問當前cookie。但“/day16”或“/day16/aaa”

        將不能訪問。

       2)cookie.setPath("/day16");

       表示【day16 項目】下的所有servlet都可以訪問當前cookie

       3)cookie.setPath("/");

       表示【tomcat下】的所有的web項目,都可以訪問當前cookie

  • cookie唯一表示:

    • 唯一標示:domain + path + name (類似Java中 包 + 類名)

      • domain 域名,不同的網站使用的是不同的域名,cookie就不同。

      • path 路徑,通過cookie.setPath(…)設置的內容。

      • name cookie名稱,通過 new Cookie(name , …) 確定的內容。

    • 例如:以下表示的是兩個cookie,可以同時存在。

      • /web/a/b/cookieName

      • /web/a/cookieName

      • 如果路徑和名稱一樣,兩次addCookie(),后者將覆蓋前者。

1.5.2 CookieAPI:

方法名

描述

getName()

獲得cookie名稱。

getValue()

獲得cookie的值。

setMaxAge(int expiry)

設置cookie的有效時間。

  • 如果沒有設置,cookie只緩存瀏覽器緩存中,瀏覽器關閉,cookie刪除。

  • 如果設置有效時間,在時間范圍內,cookie被寫入到瀏覽器端,關閉瀏覽器下次訪問仍可獲得,直到過期。

setPath(java.lang.String uri)

設置cookie允許被訪問的路徑。設置的路徑,以及子路徑都被允許訪問。

  • 例如:setPath("/web/a/b");

http://localhost:8080/web/a/b/oneServlet,可訪問(當前路徑)

http://localhost:8080/web/a/b/c/oneServlet,可訪問(子路徑)

http://localhost:8080/web/a/c/oneServlet,不允許訪問(無關路徑)

  • 常見設置:setPath(“/”) ,當前tomcat下的所有的web項目都可以訪問

第2章 案例:一次性驗證碼的校驗

2.1 需求:

  • 驗證碼的作用:

    • 防止惡意提交表單

2.2 相關知識點:

2.2.1 Session的概述

2.2.1.1 什么是Session

當人們去醫院就診時,就診病人需要辦理醫院的就診卡,該卡上只有卡號,而沒有其它信息。但病人每次去該醫院就診時,只要出示就診卡,醫務人員便可根據卡號查詢到病人的就診信息。

Session技術就好比醫院發放給病人的就醫卡和醫院為每個病人保留病例檔案的過程。當瀏覽器訪問Web服務器時,Servlet容器就會創建一個Session對象和ID屬性,其中,Session對象就相當于病歷檔案,ID就相當于就診卡號。當客戶端后續訪問服務器時,只要將標識號傳遞給服務器,服務器就能判斷出該請求是哪個客戶端發送的,從而選擇與之對應的Session對象為其服務。

需要注意的是,由于客戶端需要接收、記錄和回送Session對象的ID,因此,通常情況下,Session是借助Cookie技術來傳遞ID屬性的。

為了使讀者更好的理解Session,接下來,以網站購物為例,通過一張圖來描述Session保存用戶信息的原理,具體如圖5-5所示。

圖1-1 Session保存用戶信息的過程

在圖5-5中,用戶甲和乙都調用buyServlet將商品添加到購物車,調用payServlet進行商品結算。由于甲和乙購買商品的過程類似,在此,以用戶甲為例進行詳細說明。當用戶甲訪問購物網站時,服務器為甲創建了一個Session對象(相當于購物車)。

當甲將Nokia手機添加到購物車時,Nokia手機的信息便存放到了Session對象中。

同時,服務器將Session對象的ID屬性以Cookie (Set-Cookie: JSESSIONID=111)的形式返回給甲的瀏覽器。當甲完成購物進行結賬時,需要向服務器發送結賬請求,這時,瀏覽器自動在請求消息頭中將Cookie (Cookie: JSESSIONID=111)信息回送給服務器,服務器根據ID屬性找到為用戶甲所創建的Session對象,并將Session對象中所存放的Nokia手機信息取出進行結算。

2.2.1.2 為什么要使用會話

  • 使用servlet生成驗證碼時,我們需要在服務器記錄一份生成的隨機字符,當用戶提交填寫的數據時,將用戶輸入的數據和服務器緩存的數據進行比對。

  • 將隨機字符串保存在ServletContext中或者request中是否可以?

    • 將數據存放到ServletContext,多個用戶共享一個驗證碼。

    • 將數據存放到request作用域,多次請求不能共享數據。

  • 我們發現將數據保存到ServletContext和request中是存在問題的,那么就需要使用會話技術保存用戶的私有信息.

2.2.1.3 CookieSession的選取?

* Cookie是有大小和個數的限制的.Session存到服務器端的技術,沒有大小和個數的限制.

* Cookie相對于Session來講不安全.


2.2.1.4 如何使用Session:

Session是與每個請求消息緊密相關的,為此,HttpServletRequest定義了用于獲取Session對象的getSession()方法,該方法有兩種重載形式,具體如下。

public HttpSession getSession(boolean create)

public HttpSession getSession()

上面重載的兩個方法都用于返回與當前請求相關的HttpSession對象。不同的是,第一個getSession()方法根據傳遞的參數來判斷是否創建新的HttpSession對象,如果參數為true,則在相關的HttpSession對象不存在時創建并返回新的HttpSession對象,否則不創建新的HttpSession對象,而是返回null。第二個getSession()方法則相當于第一個方法參數為true時的情況,在相關的HttpSession對象不存在時總是創建新的HttpSession對象。

要想使用HttpSession對象管理會話數據,不僅需要獲取到HttpSession對象,還需要了解HttpSession對象的相關方法。HttpSession接口中定義的操作會話數據的常用方法如表5-2所示。

表5-1 HttpSession接口中的常用方法

方法聲明

功能描述

String getId()

用于返回與當前HttpSession對象關聯的會話標識號

long getCreationTime()

返回Session創建的時間,這個時間是創建Session的時間與19701100:00:00之間時間差的毫秒表示形式

long getLastAccessedTime()

返回客戶端最后一次發送與Session相關請求的時間,這個時間是發送請求的時間與19701100:00:00之間時間差的毫秒表示形式

void  setMaxInactiveInterval(int interval)

用于設置當前HttpSession對象可空閑的以秒為單位的最長時間,也就是修改當前會話的默認超時間隔

boolean isNew()

判斷當前HttpSession對象是否是新創建的

void invalidate()

用于強制使Session對象無效

ServletContext getServletContext()

用于返回當前HttpSession對象所屬于的WEB應用程序對象,即代表當前WEB應用程序的ServletContext對象

void setAttribite(String name,Object value)

用于將一個對象與一個名稱關聯后存儲到當前的HttpSession對象中

String getAttribute()

用于從當前HttpSession對象中返回指定名稱的屬性對象

void removeAttribute(String name)

用于從當前HttpSession對象中刪除指定名稱的屬性

5-2列舉了HttpSession接口中的常用方法,這些方法都是用來操作HttpSession對象的。

2.3 案例分析

2.4 代碼實現:

  • 將隨機生成的字母或數字存入到Session中:

  • 驗證碼的校驗:

public class LoginServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

// 進行驗證碼校驗:

String code1 = request.getParameter("checkcode");

String code2 = (String)request.getSession().getAttribute("checkcode");

request.getSession().removeAttribute("checkcode");

if(!code1.equalsIgnoreCase(code2)){

// 驗證碼有錯誤:

request.setAttribute("msg", "驗證碼輸入錯誤!");

request.getRequestDispatcher("/demo4-checkcode/login.jsp").forward(request, response);

return;

}

// 登錄代碼:

}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doGet(request, response);

}

}


2.5 作用域總結:

2.5.1 Servlet 三個作用域總結:

  • ServletContext:針對一個WEB應用。一個WEB應用只有一個ServletContext對象,使用該對象保存的數據在整個WEB應用中都有效。

    • 創建:服務器啟動的時候.

    • 銷毀:服務器關閉的時候或者項目移除的時候.

  • HttpSession:針對一次會話。使用該對象保存數據,一次會話(多次請求)內數據有效。

    • 創建:服務器第一次調用getSession()的時候.服務器創建session的對象.

    • 銷毀:

   1. 非正常關閉服務器(正常關閉:Session被序列化)

   2. Session過期了,默認時間是30分鐘.

   3. 手動調用session的invalidate的方法.

  • HttpServletRequest :針對一次請求。使用該對象保存數據,一次請求(一個頁面,如果是請求轉發多個頁面)內數據有效.

    • 創建:客戶端向服務器發送一次請求

    • 銷毀:服務器為這次請求作出響應之后,銷毀request.

  • 三個作用域對象操作的API相同

    • 存放數據:setAttribute(name,value)

    • 獲得數據:getAttribute(name)

    • 刪除數據:removeAttribute(name)


第3章 案例:記錄用戶的商品的瀏覽記錄:

3.1 需求:


3.2 案例分析

3.2.1 流程分析


3.2.2 步驟分析:

/**

* 1.接收參數ID

* 2.獲得從瀏覽器帶過來的Cookie的信息.

* 3.判斷是否是第一次瀏覽商品:

*     * 如果是第一次:

*         * 創建一個Cookie將商品ID回寫到瀏覽器.

*     * 如果不是第一次:

*         * 獲得Cookie中的值(所有瀏覽過商品的ID)  1-3

*         * 判斷現在瀏覽的商品是否已經在瀏覽器記錄中.

*             * 已經存在:1-3 點擊3

*                 * 刪除當前元素,將該元素添加到最前面.

*             * 不存在: 1-3 點擊 4  1-3-2 點擊4

*                 * 判斷長度:

*                     * 沒有超出界限:直接添加到最前面.

*                     * 如果到達界限:刪除最后面一個元素,將點擊的這個添加到最前面.

*         * 創建一個Cookie將商品的ID們回寫到瀏覽器.

* 4.頁面跳轉到商品詳情的頁面.

*/


3.3 代碼實現:

public class HistoryServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

/**

* 1.接收參數ID

* 2.獲得從瀏覽器帶過來的Cookie的信息.

* 3.判斷是否是第一次瀏覽商品:

*     * 如果是第一次:

*         * 創建一個Cookie將商品ID回寫到瀏覽器.

*     * 如果不是第一次:

*         * 獲得Cookie中的值(所有瀏覽過商品的ID)  1-3

*         * 判斷現在瀏覽的商品是否已經在瀏覽器記錄中.

*             * 已經存在:1-3 點擊3

*                 * 刪除當前元素,將該元素添加到最前面.

*             * 不存在: 1-3 點擊 4  1-3-2 點擊4

*                 * 判斷長度:

*                     * 沒有超出界限:直接添加到最前面.

*                     * 如果到達界限:刪除最后面一個元素,將點擊的這個添加到最前面.

*         * 創建一個Cookie將商品的ID們回寫到瀏覽器.

* 4.頁面跳轉到商品詳情的頁面.

*/

// 1.接收參數ID:

String id = request.getParameter("id");

// 2.獲得從客戶端帶過來的所有的Cookie:

Cookie[] cookies = request.getCookies();

// 3.查找指定名稱Cookie,

Cookie cookie = CookieUtils.findCookie(cookies, "history");

// 4.判斷是否是第一次瀏覽商品:

if(cookie == null){

// 第一次瀏覽商品:

Cookie c = new Cookie("history",id);

// 設置有效路徑:

c.setPath("/day11");

// 設置有效時長:

c.setMaxAge(7*24*60*60);

// Cookie回寫到瀏覽器:

response.addCookie(c);

}else{

// 不是第一次訪問: 1-3

// 判斷瀏覽的商品是否已經在瀏覽記錄中:

String value = cookie.getValue(); // 1-3

// 切分:

String[] ids = value.split("-"); // [1,3]

// 創建LinkedList:進行增刪改的時候比較方便.

LinkedList<String> list = new LinkedList<String>(Arrays.asList(ids));

// 判斷是否商品已經在瀏覽記錄中:

if(list.contains(id)){

// 說明商品已經在瀏覽記錄中. 1-3 點擊 3 --3-1

list.remove(id);

list.addFirst(id);

}else{

// 商品沒有在瀏覽記錄中  

if(list.size()>=3){

// 超過長度   1-3-2 點擊 4 --> 4-1-3

list.removeLast();

list.addFirst(id);

}else{

// 沒有超過    1-3 點擊 4--4-1-3

list.addFirst(id);

}

}

// 使用-連接集合中的數據:

StringBuffer sb = new StringBuffer();

for (String string : list) {

sb.append(string).append("-");

}

String history = sb.toString().substring(0, sb.toString().length()-1);

Cookie c = new Cookie("history",history);

// 設置有效路徑:

c.setPath("/day11");

// 設置有效時長:

c.setMaxAge(7*24*60*60);

// Cookie回寫到瀏覽器:

response.addCookie(c);

}

// 頁面的跳轉:

response.sendRedirect(request.getContextPath()+"/demo2-history/product_info"+id+".htm");

}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doGet(request, response);

}

}


3.4 總結:

3.4.1 清空瀏覽記錄:

public class ClearHistoryServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

// 刪除持久性的Cookie:

Cookie cookie = new Cookie("history","");

cookie.setPath("/day11");

cookie.setMaxAge(0);

response.addCookie(cookie);

response.sendRedirect(request.getContextPath()+"/demo2-history/product_list.jsp");

}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doGet(request, response);

}

}

3.4.2 擴展:另一種實現流程

3.4.3 擴展:顯示多個瀏覽歷史記錄

第4章 總結



支付寶贊助-Java幫幫社區
微信贊助-Java幫幫社區
Java幫幫公眾號生態

Java幫幫公眾號生態

總有一款適合你

Java幫幫-微信公眾號

Java幫幫-微信公眾號

將分享做到極致

Python幫幫-公眾號

Python幫幫-公眾號

人工智能,爬蟲,學習教程

大數據驛站-微信公眾號

大數據驛站-微信公眾號

一起在數據中成長

九點編程-公眾號

九點編程-公眾號

深夜九點學編程

程序員生活志-公眾號

程序員生活志-公眾號

互聯網,職場,程序員那些事兒

Java幫幫學習群生態

Java幫幫學習群生態

總有一款能幫到你

Java學習群

Java學習群

與大牛一起交流

大數據學習群

大數據學習群

在數據中成長

九點編程學習群

九點編程學習群

深夜九點學編程

python學習群

python學習群

人工智能,爬蟲

測試學習群

測試學習群

感受測試的魅力

Java幫幫生態承諾

Java幫幫生態承諾

一直堅守,不負重望

初心
勤儉
誠信
正義
分享
合作品牌 非盈利生態-優質內容分享傳播者
關于我們
友鏈申請
友鏈交換:加幫主QQ2524138991 留言即可 24小時內答復  
全站內容非商業用途,內容來源于網友,并遵循 許可,如有異議請聯系客服。
會員登錄
獲取驗證碼
登錄
登錄
我的資料
留言
回到頂部