1. 程式人生 > >01-4 會話技術

01-4 會話技術

首先思考一個問題:

在無登陸情況下訪問購物網站,仍然可以新增商品到購物車,那麼這是什麼原因呢?

猜想:

1.資料存放在資料庫

錯誤,無法儲存,沒有主鍵(使用者名稱).也不可能ip地址做主鍵

2.封裝在request和response域物件中

錯誤,域物件的作用範圍很有限,僅在當前訪問內有效,即使採用轉發把request,response傳到別的servlet,那麼加入購物車(訪問購物車servlet)後會立即轉到付款servlet

3.封裝到servletcontext

servletcontext的作用域是整個專案,一個文字物件只有一個servletcontext,後面使用者的k-v會把前面使用者的k-v覆蓋,所以不行

實際上是採用的會話技術,即cookie和session


【會話技術】


 從開啟一個瀏覽器訪問某個站點,到關閉這個瀏覽器的整個過程,成為一次會話。
 會話技術就是記錄這次會話中客戶端的狀態與資料的。

 會話技術分為Cookie和Session:
 Cookie:資料儲存在客戶端本地,減少伺服器端的儲存的壓力,安全性不好,客戶端可以清除cookie
 Session:將資料儲存到伺服器端,安全性相對好,增加伺服器的壓力

【Cookie】


 Cookie技術是將使用者的資料儲存到客戶端的技術

cookie機制

那麼本文開頭的購物網站是如何儲存購物車內容的?

 1. 伺服器端向客戶端傳送一個Cookie

  1)建立Cookie:
  Cookie cookie = new Cookie(String cookieName,String cookieValue);
  示例:
  Cookie cookie = new Cookie("username","zhangsan");
  那麼該cookie會以響應頭的形式傳送給客戶端:

  注意:Cookie中不能儲存中文,也不是域物件

  2)設定Cookie在客戶端的持久化時間:


  cookie.setMaxAge(int seconds); ---時間秒

  注意:如果不設定持久化時間,cookie會儲存在瀏覽器的記憶體中,
  瀏覽器關閉cookie資訊銷燬(會話級別的cookie),
  如果設定持久化時間,cookie資訊會被持久化到瀏覽器的磁碟檔案裡

  示例:
  cookie.setMaxAge(10*60);
  設定cookie資訊在瀏覽器的磁碟檔案中儲存的時間是10分鐘,過期瀏覽器自動刪除該cookie資訊

  3)設定Cookie的攜帶路徑:
  cookie.setPath(String path);
  注意:如果不設定攜帶路徑,那麼該cookie資訊會在訪問產生該cookie的web資源所在的路徑都攜帶cookie資訊
  示例:
  cookie.setPath("/WEB16");
  代表訪問WEB16應用中的任何資源都攜帶cookie
  cookie.setPath("/WEB16/cookieServlet");
  代表訪問WEB16中的cookieServlet時才攜帶cookie資訊

  4)向客戶端傳送cookie:
  response.addCookie(Cookie cookie);

package com.wowowo.cookie;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/cookie")
public class CookieServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

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

		// cookie分為記憶體形式和檔案形式(預設的是記憶體形式,瀏覽器關閉了cookie就刪除)
		//新建一個cookie,不允許有中文
		Cookie cookie = new Cookie("gundam", "freedom");

		// 設定銷燬時間,以秒為單位,設定了時間的cookie是檔案形式,不會隨瀏覽器關閉而刪除
		cookie.setMaxAge(5 * 60);

		//訪問某個資源會攜帶cookie
		//cookie.setPath("/my1022/cookie");

		//訪問my1022專案下的資源會攜帶cookie
		// cookie.setPath("/my1022/");

		//對主機下所有資源會攜帶cookie
		cookie.setPath("/");

		// 在response物件裡新增cookie
		response.addCookie(cookie);

		response.getWriter().append("Served at: ").append(request.getContextPath());

	}

}

 

  5)刪除客戶端的cookie:
  如果想刪除客戶端已經儲存的cookie資訊,那麼就使用同名同路徑的持久化時間為0的cookie進行覆蓋即可

//新增一個同名空值,同路徑,持久化時間為0秒的cookie
		Cookie  cookie=new Cookie("gundam","");
		cookie.setMaxAge(0);
		cookie.setPath("/");
		response.addCookie(cookie);

 2.伺服器端怎麼接受客戶端攜帶的Cookie

 cookie資訊是以請求頭的方式傳送到伺服器端的:

 瀏覽器每次訪問都會把url對應的cookie傳給伺服器

  //1)通過request獲得所有的Cookie:
   Cookie[] cookies = request.getCookies();
  //2)遍歷Cookie陣列,通過Cookie的名稱獲得我們想要的Cookie
   for(Cookie cookie : cookies){
     if(cookie.getName().equal(cookieName)){
       String cookieValue = cookie.getValue();
     }
   }

注意:有些for each迴圈在不知道陣列是否為空的情況下需要判斷:

1.遍歷資料夾

2.遍歷cookies陣列


 

例題:
/1. 寫一個Servlet, 訪問它可以顯示出使用者上一次的訪問時間 
訪問時間以cookie形式儲存一個月. 如果是第一次訪問, 就顯示你是第一次訪問

package com.wowowo.cookie;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jdk.nashorn.internal.runtime.regexp.joni.Config;

@WebServlet("/show")
public class ShowCookieTime extends HttpServlet {
	private static final long serialVersionUID = 1L;

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

		// 設定編碼格式為utf-8
		response.setContentType("text/html;charset=UTF-8");
		// 獲取cookies陣列
		Cookie[] cookies = request.getCookies();

		// 設定一個標誌位,用來判斷是否是第一次登入
		boolean isFirst = true;
		// cookie不為空的情況下進行遍歷,防止空指標
		if (cookies != null) {
			// 遍歷cookies,查詢是否是第一次訪問(查詢cookie的name為time是否存在)
			for (Cookie cookie1 : cookies) {
				// 存在name為time的鍵值對
				if ("time".equals(cookie1.getName())) {
					isFirst = false;
					// 列印上一次訪問時間
					response.getWriter().write("上一次訪問時間" + cookie1.getValue());
					// break可加可不加,加的話提高效率
					break;
				}
			}

		}
		// isFirst為false的情況為: cookie不為空而且裡面有一個name為time的鍵值對,也就是說不是第一次訪問
		// 反過來就是cookie為空或者cookie內沒有time鍵值對,表示第一次訪問
		if (isFirst) {
			response.getWriter().write("第一次訪問");
		}
		// 包裝一個cookie帶格式化當前時間的鍵值對新增到響應物件傳送過去
		Cookie cookie = new Cookie("time", new SimpleDateFormat("YYYY-MM-dd HH:mm:ss").format(new Date()));
		cookie.setPath("ShowCookieTime/show");
		cookie.setMaxAge(30 * 24 * 60 * 60);
		response.addCookie(cookie);

	}

}

 


【Session】

session的機制

此處舉個存包系統的例子,方便理解session的機制:

牌子儲存在寄包人--sessionid(儲存在瀏覽器的cookie裡面)

包儲存在櫃子--session的內容(儲存在伺服器)

1.第一次寄包(第一次訪問伺服器)

管理員會發放一塊牌子,牌子的號碼對應包在櫃子所放的位置

伺服器如果發現cookie中不存在sessionid,那麼就會新建一個session並把sessionid返回給使用者

2.包寄存在櫃子裡,想來拿包(不是第一次訪問伺服器)

寄包人把牌子給管理員,管理員根據牌子的號碼找到包

瀏覽器把sessionid放在請求頭的cookie中傳送到伺服器,伺服器根據sessionid獲取相應的session內容做進一步處理

 

 


 Session技術是將資料儲存在伺服器端的技術,會為每個客戶端都建立一塊記憶體空間儲存客戶的資料,
 但客戶端需要每次都攜帶一個標識ID去伺服器中尋找屬於自己的記憶體空間。
 所以說Session的實現是基於Cookie,
 Session需要藉助於Cookie儲存客戶的唯一性標識JSESSIONID

  1.獲得Session物件
   HttpSession session = request.getSession();
   此方法會獲得專屬於當前會話的Session物件,

  •    如果伺服器端沒有該會話的Session物件會建立一個新的Session返回,
  •    如果已經有了屬於該會話的Session直接將已有的Session返回

  (實質就是根據JSESSIONID判斷該客戶端是否在伺服器上已經存在session了)

  2.怎樣向session中存取資料(session也是一個域物件)
   Session也是儲存資料的區域物件,所以session物件也具有如下三個方法:
   session.setAttribute(String name,Object obj);
   session.getAttribute(String name);
   session.removeAttribute(String name);

  3.Session物件的生命週期(面試題/筆試題)
   建立:第一次執行request.getSession()時建立
   銷燬:
   1)伺服器(非正常)關閉時

   2)session過期/失效(預設30分鐘)

   問題:時間的起算點 從何時開始計算30分鐘?
    從不操作伺服器端的資源開始計時

   可以在工程的web.xml中進行配置

右鍵專案名-->java ee tools-->generate deployment discriptior stub

單位是分鐘
   <session-config>
        <session-timeout>30</session-timeout>
   </session-config>

   3)手動銷燬session
     session.invalidate();

  作用範圍:
  預設在一次會話中,也就是說在,一次會話中任何資源公用一個session物件

  面試題:瀏覽器關閉,session就銷燬了? 不對

瀏覽器關閉時銷燬的是cookie中的sessionid,session還在伺服器中,只是客戶端找不到session了而已

如果想不銷燬sessionid那麼可以對cookie設定持久化時間,把cookie變成檔案形式永久儲存

 

session、request、和ServletContext的區別?

從作用域,生命週期2方面闡述

https://blog.csdn.net/qq_24341213/article/details/52843831

 

練習:用servlet實現如圖效果

登陸頁面對應的servlet

package com.wowowo.hw;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.websocket.Session;

/**
 * Servlet implementation class LoginServlet
 */
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//把sessionid(cookie裡面存放sessionid)設為10分鐘銷燬
		HttpSession session = request.getSession();
		Cookie cookie = new Cookie("JSESSIONID", session.getId());
		cookie.setMaxAge(10 * 60);
		cookie.setPath("/my1022/welcome");
		response.addCookie(cookie);
		//把表單提交的使用者名稱密碼進行驗證
		String uname = request.getParameter("uname");
		String upwd = request.getParameter("upwd");
		//密碼正確,把使用者名稱放到session內,重定向到歡迎頁面
		if ("user".equals(uname) && "123".equals(upwd)) {
			session.setAttribute("uname", uname);
			response.sendRedirect("/my1022/welcome");
		} else {
			//密碼錯誤
			response.getWriter().write("failed");
		}

	}

}

歡迎頁面對應的servlet

package com.wowowo.hw;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet("/welcome")
public class WelcomeServlet extends HttpServlet {
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		HttpSession session = request.getSession();
		//判斷登陸狀態(登陸狀態就是看session內是否有name屬性)
		if (session.getAttribute("uname") != null) {
			response.getWriter().write("welcome:" + session.getAttribute("uname"));
		} else {
			response.sendRedirect("/my1022/login.html");
		}
	}
}