1. 程式人生 > >javaweb:會話管理和儲存會話資料的兩種技術(Cookie、Session)

javaweb:會話管理和儲存會話資料的兩種技術(Cookie、Session)

會話:

什麼是會話?

會話可簡單理解為:使用者開一個瀏覽器,點選多個超連結,訪問伺服器多個web資源,然後關閉瀏覽器,整個過程稱之為一個會話

會話過程中要解決的一些問題?

每個使用者與伺服器進行互動的過程中,各自會有一些資料,程式要想辦法儲存每個使用者的資料。

例如:使用者點選超連結通過一個servlet購買了一個商品,程式應該儲存使用者購買的商品,以便於使用者點結帳servlet時,結帳servlet可以得到使用者商品為使用者結帳。

儲存會話資料的兩種技術:

Cookie

Cookie是客戶端技術,程式把每個使用者的資料以cookie的形式寫給使用者各自的瀏覽器。當用戶使用瀏覽器再去訪問伺服器中的

web資源時,就會帶著各自的資料去。這樣,web資源處理的就是使用者各自的資料了。

Session

Session是伺服器端技術,利用這個技術,伺服器在執行時可以為每一個使用者的瀏覽器建立一個其獨享的session物件,由於session為使用者瀏覽器獨享,所以使用者在訪問伺服器的web資源時,可以把各自的資料放在各自的session中,當用戶再去訪問伺服器中的其它web資源時,其它web資源再從使用者各自的session中取出資料為使用者服務。

Cookie技術:

Cookie快速入門:

Cookie 是一個小的文字資料,由伺服器端生成,傳送給客戶端瀏覽器,客戶端瀏覽器如果設定為啟用  Cookie,則會將這個小文字資料

儲存到某個目錄下的文字檔案內。

下次登入同一頁面,瀏覽器則會自動將Cookie傳回伺服器端。

Cookie 值的形式:key-value

顯示使用者上次訪問時間

判斷使用者是否是第一次訪問

如果是第一次訪問,需要輸出歡迎,並且記錄當前的時間,儲存到cookie中,再回寫到瀏覽器端。

如果不是第一次訪問,獲取cookie中的時間,輸出時間,並且記錄當前的時間,儲存到cookie中,再回寫到瀏覽器端。

                                                                                Cookie

相當於一個證書

Cookie API:

ljavax.servlet.http.Cookie類用於建立一個Cookieresponse介面也中定義了一個addCookie方法,它用於在其響應頭中增加一個相應的Set-Cookie頭欄位。 同樣,request介面中也定義了一個getCookies方法,它用於獲取客戶端提交的CookieCookie類的方法:

üpublic Cookie(String name,String value)

üsetValuegetValue方法

üsetMaxAgegetMaxAge方法

üsetPathgetPath方法

üsetDomaingetDomain方法

ügetName方法

Cookie細節:

l一個Cookie只能標識一種資訊,它至少含有一個標識該資訊的名稱(NAME)和設定值(VALUE)。

l一個WEB站點可以給一個WEB瀏覽器傳送多個Cookie,一個WEB瀏覽器也可以儲存多個WEB站點提供的Cookie

l瀏覽器一般只允許存放300Cookie每個站點最多存放20Cookie每個Cookie的大小限制為4KB

l如果建立了一個cookie,並將他傳送到瀏覽器,預設情況下它是一個會話級別的cookie(即儲存在瀏覽器的記憶體中),使用者退出瀏覽器之後即被刪除。若希望瀏覽器將該cookie儲存在磁碟上,則需要使用maxAge,並給出一個以秒為單位的時間。

刪除持久cookie,可以將cookie最大時效設為0注意,刪除cookie時,path必須一致,否則不會刪除

Cookie應用:

1.使用者驗證簡略化。ID、密碼作為cookie資訊傳送給使用者,在以後的訪問中可以獲得到cookie,簡化輸入。

2.網上購物等應用。每將一個商品放入購物車,就會發送cookie給使用者。

3.把握使用者訪問的時間。訪問時,將時間作為cookie傳送給使用者,退出時將該cookie返回給web伺服器,這樣可以掌握訪問該站點的時間長度。

4.推薦系統與搜尋引擎。

•5編寫商品資訊列表,給每個商品起唯一的id值,通過id傳值。

•6判斷是否是第一次訪問

•7如果是第一次訪問,建立cookie,記錄商品id,回寫到瀏覽器

•8如果不是第一次訪問,獲取cookie中的商品資訊,但是需要判斷cookie中是否已經包含該商品,如果包含就不用處理,如果不包含,可以取出商品的id,累加操作。(可以編寫一個判斷是否包含的方法

•9重定向到商品列表頁面,把商品迴圈到列表頁面

•10清除瀏覽記錄

顯示上次瀏覽商品的實現過程:

Cookie 操作主要用到以下幾個方法:

response.addCookie(Cookie c):將 Cookie 寫入客戶端

Cookie.setMaxAge(int second):設定 Cookie 有效時間

寫入Cookie的過程:

步驟1:建立cookie物件。Cookie建構函式(名稱、值),皆為字串型別。

步驟2:設定有效時間。sexMaxAge(),單位為s(秒)。

步驟3:寫入Http響應報文。通過response.addCookie完成。

Cookie 讀取操作:

讀取客戶端 Cookie方法

Cookie[]  request.getCookies():讀取客戶端所有 Cookie,以陣列形式返回。然後再遍歷陣列,根據名稱找到所需的Cookie.

從客戶端讀取cookie:

步驟1:呼叫request.getCookies( )

步驟2:對陣列進行迴圈,呼叫每個cookiegetName方法,直到找到感興趣的cookie位置。

Cookie的安全性:

盜取的方法:

利用跨站指令碼技術,將資訊發給目標伺服器;為了隱藏 URL,甚至可以結合 Ajax(非同步 Javascript 和 XML 技術)在後臺竊取 Cookie

通過某些軟體,竊取硬碟下的  Cookie。一般說來,當用戶訪問完某站點後,Cookie檔案會存在機器的某個資料夾下,因此可以通過某些盜取和分析軟體來盜取  Cookie。

利用客戶端指令碼盜取 Cookie。在 Javascript 中有很多 API 可以讀取客戶端 Cookie,可以將這些程式碼隱藏在一個程式(如畫圖)中,很隱祕地得到 Cookie 的值

例子>顯示使用者訪問時間:

建立MyCookieUtil類,在裡面寫一個判斷cookieshu的方法:

package cn.itcast.utils;

import javax.servlet.http.Cookie;

/**
 * 操作cookie
 * @author Administrator
 *
 */
public class MyCookieUtil {
	
	/**
	 * 通過cookie的名稱來獲取指定的cookie,如果找到返回cookie,如果找不到,返回null
	 * @param cookies
	 * @param cookieName
	 * @return
	 */
	public static Cookie getCookieByName(Cookie [] cookies,String cookieName){
		// 如果cookies陣列為空,返回null
		if(cookies == null){
			return null;
		}else{
			// 如果不為空,迴圈遍歷,拿到每一個cookie,和cookieName去判斷,如果匹配成功了,返回。
			for (Cookie cookie : cookies) {
				// 拿到每一個cookie,和cookieName去判斷,如果匹配成功了,返回。
				// 獲取cookie的名稱
				if(cookie.getName().equals(cookieName)){
					// 匹配成功了
					return cookie;
				}
			}
			return null;
		}
	}

}











LasTimeServlet.java,在此類中呼叫MyCookieUtil類的getCookieByName方法:

package cn.itcast.cookie;

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

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.itcast.utils.MyCookieUtil;

/**
 * 顯示使用者上次的訪問時間
 * @author Administrator
 *
 */
public class LatTimeServlet extends HttpServlet {
	private static final long serialVersionUID = -6068764497514719951L;

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/**
		 * 1.先判斷是否是第一次訪問?因為:第一次訪問和第n次處理的業務是不同的。
		 * 2.如果是第一次訪問:先輸出一句歡迎,記錄當前的時間,儲存到cookie中,回寫到瀏覽器端。
		 * 3.如果不是第一次訪問,獲取cookie中的值(就是你上次的訪問的時間),把時間輸出到頁面上。記錄當前的時間,儲存到cookie中。回寫到瀏覽器端。
		 */
		
		// 設定字元中文亂碼的問題
		response.setContentType("text/html;charset=UTF-8");
		
		// 先判斷是否是第一次訪問?先獲取所有的cookie陣列,查詢咱們定義的cookie。
		// 如果找到咱們定義的cookie,說明不是第一次訪問。如果沒找到,那就是說明是第一次訪問。
		// 獲取cookie的陣列
		Cookie [] cookies = request.getCookies();
		// 查詢自己定義的cookie,查詢指定名稱的cookie。	(Cookie c = new Cookie("last","cookie的值"));
		Cookie cookie = MyCookieUtil.getCookieByName(cookies, "last");
		// 記錄當前的時間
		Date date = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		// 當前的時間的字串
		String sDate = sdf.format(date);
		// 如果cookie為null,說明是第一次訪問
		if(cookie == null){
			// 我是第一次訪問
			// 輸出一句話
			response.getWriter().print("<h3>親,帶錢再來哦!!</h3>");
			// 記錄當前的時間
			// 把當前的時間回儲存cookie中
			Cookie c = new Cookie("last", sDate);
			
			// 設定有效時間
			c.setMaxAge(60*60);	// 1小時
			c.setPath("/day11"); // 有效路徑就變成了/day11
			// 回寫
			response.addCookie(c);
		}else{
			// 獲取上次的訪問時間(從cookie中獲取)
			String lasttime = cookie.getValue();
			// 把上次的時間輸出到頁面上去
			response.getWriter().print("<h3>親,您上次的訪問時間是"+lasttime+",下次快點來哦!!</h3>");
			// 記錄當前的時間
			cookie.setValue(sDate);
			
			// 設定有效時間
			cookie.setMaxAge(60*60);	// 1小時
			cookie.setPath("/day11"); // 有效路徑就變成了/day11
			
			// 回寫
			response.addCookie(cookie);
		}
	}

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

		doGet(request, response);
	}

}

例子:商品的瀏覽記錄:

前臺程式:

productList.jsp

<%@page import="cn.itcast.utils.MyCookieUtil"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>商品的列表頁面</title>

<style type="text/css">
	.img1{
		width: 160px;
		height: 140px;
	}
	.img2{
		width: 80px;
		height: 70px;
	}

</style>

</head>
<body>

	<img class="img1" src="/day11/img/1.jpg"><a href="/day11/product?id=1">手電筒</a>
	<img class="img1" src="/day11/img/2.jpg"><a href="/day11/product?id=2">電話</a>
	<img class="img1" src="/day11/img/3.jpg"><a href="/day11/product?id=3">電視</a>
	<br/>
	<img class="img1" src="/day11/img/4.jpg"><a href="/day11/product?id=4">冰箱</a>
	<img class="img1" src="/day11/img/5.jpg"><a href="/day11/product?id=5">手錶</a>
	<img class="img1" src="/day11/img/6.jpg"><a href="/day11/product?id=6">電腦</a>
	
	<h3>商品的瀏覽器記錄</h3>
	<h4><a href="/day11/removeProduct">清除瀏覽記錄</a></h4>
	
<%
	// 獲取到cookie的內容 可以把cookie的內容動態的顯示到頁面上
	Cookie [] cookies = request.getCookies();
	// 通過指定名稱來獲取cookie
	Cookie cookie = MyCookieUtil.getCookieByName(cookies, "product");
	// 判斷cookie不為空
	if(cookie != null){
		// 獲取cookie的值
		String longid = cookie.getValue();		// product=1,2,3
		// 切割
		String [] ids = longid.split(",");
		// 迴圈遍歷
		for(String id : ids){
%>
		<img class="img2" src="/day11/img/<%= id %>.jpg">++++"/day11/img/<%= id %>.jpg"
<%			
			
		}
	}
%>	
	
</body>
</html>






後臺程式:

ProdcutServlet.java 

package cn.itcast.cookie;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.itcast.utils.MyCookieUtil;

/**
 * 商品瀏覽記錄的後臺
 * @author Administrator
 *
 */
public class ProductServlet extends HttpServlet {
	private static final long serialVersionUID = -5747737695587699577L;

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/**
		 * 0.獲取傳過來id值
		 * 1.判斷是否是第一次訪問?(獲取指定名稱的cookie如果為null,說明是第一次訪問)
		 * 		* 如果是第一次訪問,把商品的id儲存到cookie中,回寫cookie。
		 * 		* 如果不是第一次訪問
		 * 			* 先獲取cookie中的內容,進行判斷(判斷cookie中是否包含當前點選的商品)
		 * 				* 如果cookie中已經包含了該商品,那麼就不用處理了
		 * 				* 如果不包含,在cookie中追加該商品	product=1	product=1,2
		 * 2.重定向商品的列表頁面
		 * 3.需要在商品的列表頁面中獲取cookie的中內容,把內容顯示到頁面上。
		 */
		// 先獲取商品的id
		String id = request.getParameter("id");
		// 獲取cookie的陣列
		Cookie [] cookies = request.getCookies();
		// 查詢指定名稱的cookie
		Cookie cookie = MyCookieUtil.getCookieByName(cookies, "product");
		// 如果cookie為null,說明是第一次訪問,把商品的id儲存到cookie中,回寫
		if(cookie == null){
			// 是第一次
			Cookie c = new Cookie("product",id);
			
			// 設定有效時間
			c.setMaxAge(60*60*24);
			
			// 設定有效的路徑
			c.setPath("/day11");
			
			// 回寫
			response.addCookie(c);
		}else{
			// 說明cookie不為空
			// 先獲取cookie的內容(拿出來做判斷),cookie有可能包含當前的商品
			String longid = cookie.getValue();		// product=1,2,3		假如說當前點選的是4	product=4,1,2,3
			// 判斷字串ids是否包含當前的id
			// 把ids字串切割成陣列
			String [] ids = longid.split(",");
			if(!checkId(ids,id)){
				// 說明不包含該商品
				cookie.setValue(id+","+longid);
				
				cookie.setMaxAge(60*60*24);
				
				// 設定有效的路徑
				cookie.setPath("/day11");
				
				// 回寫cookie
				response.addCookie(cookie);
			}
		}
		// 重定向或者轉發(使用request域儲存內容,必須是轉發)request.getContextPath()獲取虛擬路徑,預設和專案名稱相同
		response.sendRedirect(request.getContextPath()+"/cookie/productList.jsp");
	}
	
	/**
	 * 判斷ids的陣列中是否包含id的值
	 * @param ids
	 * @param id
	 * @return
	 */
	private boolean checkId(String[] ids, String id) {
		for (String s : ids) {
			// 獲取s和id匹配
			if(s.equals(id)){
				// 包含
				return true;
			}
		}
		// 不包含
		return false;
	}

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

		doGet(request, response);
	}

}





session:

lWEB開發中,伺服器可以為每個使用者瀏覽器建立一個會話物件(session物件),注意:一個瀏覽器獨佔一個session物件(預設情況下)。因此,在需要儲存使用者資料時,伺服器程式可以把使用者資料寫到使用者瀏覽器獨佔的session中,當用戶使用瀏覽器訪問其它程式時,其它程式可以從使用者的session中取出該使用者的資料,為使用者服務。

lSessionCookie的主要區別在於:

Cookie是把使用者的資料寫給使用者的瀏覽器。

Session技術把使用者的資料寫到使用者獨佔的session中(伺服器端)。

lSession物件由伺服器建立,開發人員可以呼叫request物件的getSession方法得到session物件。

session為每個瀏覽器儲存資料:

session實現原理:

session案例:

l使用Session完成簡單的購物車功能

接收傳過來的商品id

使用Map集合程式碼購物車(key商品名稱,value商品數量)

session中獲取購物車

如果獲取不到,是第一次,建立Map,存入商品和數量

如果獲取到,不是第一次,拿到Map,判斷Map中是否包含商品,如果包含取出數量+1,如果不存在,直接存入。

把購物車存入到session

瀏覽器禁用Cookie後的session處理:

實驗演示禁用Cookieservlet共享資料導致的問題。

l解決方案:URL重寫

response. encodeRedirectURL(java.lang.String url)

用於對sendRedirect方法後的url地址進行重寫。

response. encodeURL(java.lang.String url)

用於對錶單action和超連結的url地址進行重寫

session建立和銷燬:

session的建立

伺服器啟動,第一次訪問呼叫getSession()方法時,建立session

Session的銷燬

伺服器非正常關閉(正常關閉不會銷燬,會序列化到work目錄)

Session過期

呼叫sessioninvalidate()方法銷燬

session案例:

l利用Session實現一次性驗證碼使用者登陸

在生成的驗證碼的servlet中使用session存入生成的驗證碼(使用StringBuffer拼接字元)

在校驗的servlet中獲取表單輸入的驗證碼和session中儲存的驗證碼

獲取到兩個不同來源的驗證碼後做對比

session案例一次性校驗碼:

l一次性驗證碼的主要目的就是為了限制人們利用工具軟體來暴力猜測密碼。

l伺服器程式接收到表單資料後,首先判斷使用者是否填寫了正確的驗證碼,只有該驗證碼與伺服器端儲存的驗證碼匹配時,伺服器程式才開始正常的表單處理流程。

l密碼猜測工具要逐一嘗試每個密碼的前題條件是先輸入正確的驗證碼,而驗證碼是一次性有效的,這樣基本上就阻斷了密碼猜測工具的自動地處理過程

Servlet的資料訪問範圍:

lapplication Scope  servletContext (資料庫連線池,配置, 執行緒池, 站點訪問次數)

每一個Web應用對應一個ServletContext

存放所有使用者都可以訪問的資料

lsession Scope HttpSession (存放與使用者相關資料)

存放每個使用者自己會話過程中的資料

lrequest Scope  HttpServletRequest

l(Servlet處理結果,JSP顯示

資料存放在request物件中

生成新的請求時,原request存放資料丟失

Cookie 和 Session 的比較:

Cookie是存放在客戶端的。Session物件是存放在伺服器端,但通常需要藉助Cookie來存放個JSESSIONID號。

Cookie只能存放文字資訊,而且大小受限。Session物件中可以存放任何型別資訊

Cookie可以長時間儲存在客戶端。Session物件在瀏覽器關閉後就失效了Session資料存放在伺服器記憶體。