摘要:保存中文上面我們的例子保存的是英文字符,下面我們來看下保存中文字符會怎么樣。出異常了中文屬于字符,英文數據字符,中文占個字符或者個字符,英文占個字符。如果為,則表示刪除該。的值規定為域名的隱私安全機制決定是不可跨域名的。
什么是會話技術
基本概念: 指用戶開一個瀏覽器,訪問一個網站,只要不關閉該瀏覽器,不管該用戶點擊多少個超鏈接,訪問多少資源,直到用戶關閉瀏覽器,整個這個過程我們稱為一次會話.為什么我們要使用會話技術?
會話跟蹤技術可以解決我們很多很多問題。
在論壇登陸的時候,很多時候會有一個小框框問你是否要自動登陸,當你下次登陸的時候就不用輸入密碼了
根據我以前瀏覽過的商品,猜我喜歡什么商品
Cookie會話跟蹤技術有Cookie和Session,Cookie技術是先出現的。我們先講Cookie技術吧。
什么是CookieCookie是由W3C組織提出,最早由netscape社區發展的一種機制
網頁之間的交互是通過HTTP協議傳輸數據的,而Http協議是無狀態的協議。無狀態的協議是什么意思呢?一旦數據提交完后,瀏覽器和服務器的連接就會關閉,再次交互的時候需要重新建立新的連接。
服務器無法確認用戶的信息,于是乎,W3C就提出了:給每一個用戶都發一個通行證,無論誰訪問的時候都需要攜帶通行證,這樣服務器就可以從通行證上確認用戶的信息。通行證就是Cookie
Cookie的流程:瀏覽器訪問服務器,如果服務器需要記錄該用戶的狀態,就使用response向瀏覽器發送一個Cookie,瀏覽器會把Cookie保存起來。當瀏覽器再次訪問服務器的時候,瀏覽器會把請求的網址連同Cookie一同交給服務器。
Cookie APICookie類用于創建一個Cookie對象
response接口中定義了一個addCookie方法,它用于在其響應頭中增加一個相應的Set-Cookie頭字段
request接口中定義了一個getCookies方法,它用于獲取客戶端提交的Cookie
常用的Cookie方法:
public Cookie(String name,String value)
setValue與getValue方法
setMaxAge與getMaxAge方法
setPath與getPath方法
setDomain與getDomain方法
getName方法
簡單使用Cookie創建Cookie對象,發送Cookie給瀏覽器、
//設置response的編碼 response.setContentType("text/html;charset=UTF-8"); //創建Cookie對象,指定名稱和值 Cookie cookie = new Cookie("username", "zhongfucheng"); //向瀏覽器給一個Cookie response.addCookie(cookie); response.getWriter().write("我已經向瀏覽器發送了一個Cookie");
瀏覽器本身沒有任何Cookie
訪問Servlet1,再回到文件夾中,還是沒有發現Cookie,這是為什么呢?我明明向瀏覽器發送了一個Cookie的。
原來發送Cookie給瀏覽器是需要設置Cookie的時間的。在給瀏覽器之前,設置一下Cookie的時間
//設置Cookie的時間 cookie.setMaxAge(1000);
再次訪問,已經發現文件夾中多了個Cookie的文本了
Cookie細節 Cookie不可跨域名性很多人在初學的時候可能有一個疑問:在訪問Servlet的時候瀏覽器是不是把所有的Cookie都帶過去給服務器,會不會修改了別的網站的Cookie
答案是否定的。Cookie具有不可跨域名性。瀏覽器判斷一個網站是否能操作另一個網站的Cookie的依據是域名。所以一般來說,當我訪問baidu的時候,瀏覽器只會把baidu頒發的Cookie帶過去,而不會帶上google的Cookie。
Cookie保存中文上面我們的例子保存的是英文字符,下面我們來看下保存中文字符會怎么樣。
response.setContentType("text/html;charset=UTF-8"); PrintWriter printWriter = response.getWriter(); String name = "中國"; Cookie cookie = new Cookie("country", name); cookie.setMaxAge(2000); response.addCookie(cookie); printWriter.write("我頒發了一個Cookie,值保存的是中文數據");
訪問Servlet1,好吧。出異常了!
中文屬于Unicode字符,英文數據ASCII字符,中文占4個字符或者3個字符,英文占2個字符。
解決:Cookie使用Unicode字符時需要對Unicode字符進行編碼。
//對Unicode字符進行編碼 Cookie cookie = new Cookie("country", URLEncoder.encode(name, "UTF-8"));
再次訪問Servlet1,已經把Cookie成功頒發給瀏覽器了
我們發現Cookie保存在硬盤的中文數據是經過編碼的,那么我們在取出Cookie的時候要對中文數據進行解碼
Cookie[] cookies = request.getCookies(); for (int i = 0; cookies != null && i < cookies.length; i++) { String name = cookies[i].getName(); //經過URLEncoding就要URLDecoding String value = URLDecoder.decode(cookies[i].getValue(), "UTF-8"); printWriter.write(name + "------" + value); }
取出存進Cookie的值
Cookie的有效期Cookie的有效期是通過setMaxAge()來設置的。
如果MaxAge為正數,瀏覽器會把Cookie寫到硬盤中,只要還在MaxAge秒之前,登陸網站時該Cookie就有效【不論關閉了瀏覽器還是電腦】
如果MaxAge為負數,Cookie是臨時性的,僅在本瀏覽器內有效,關閉瀏覽器Cookie就失效了,Cookie不會寫到硬盤中。Cookie默認值就是-1。這也就為什么在我第一個例子中,如果我沒設置Cookie的有效期,在硬盤中就找不到對應的文件。
如果MaxAge為0,則表示刪除該Cookie。Cookie機制沒有提供刪除Cookie對應的方法,把MaxAge設置為0等同于刪除Cookie
Cookie的修改和刪除上面我們已經知道了Cookie機制沒有提供刪除Cookie的方法。其實細心點我們可以發現,Cookie機制也沒有提供修改Cookie的方法。那么我們怎么修改Cookie的值呢?
Cookie存儲的方式類似于Map集合,如下圖所示
Cookie的名稱相同,通過response添加到瀏覽器中,會覆蓋原來的Cookie。
以country為名保存的是%E4%B8%AD%E5%9B%BD,下面我再以country為名,把值改變一下。
String name = "看完博客就點贊"; //對Unicode字符進行編碼 Cookie cookie = new Cookie("country", URLEncoder.encode(name, "UTF-8"));
再次查看Cookie的時候,值已經改變了,但是文件還是那一份
現在我要刪除該Cookie,把MaxAge設置為0,并添加到瀏覽器中即可
String name = "看完博客就點贊"; //對Unicode字符進行編碼 Cookie cookie = new Cookie("country", URLEncoder.encode(name, "UTF-8")); //一定不要忘記添加到瀏覽器中 cookie.setMaxAge(0); response.addCookie(cookie); printWriter.write("我刪除了該Cookie");
訪問Servlet,在硬盤已經找不到Cookie的文件了!
注意:刪除,修改Cookie時,新建的Cookie除了value、maxAge之外的所有屬性都要與原Cookie相同。否則瀏覽器將視為不同的Cookie,不予覆蓋,導致刪除修改失敗!
我們來試驗一下把。
String name = "看完博客就點贊"; //對Unicode字符進行編碼 Cookie cookie = new Cookie("country", URLEncoder.encode(name, "UTF-8")); //一定不要忘記添加到瀏覽器中 cookie.setMaxAge(10000); response.addCookie(cookie);
上面新建了一個Cookie,我修改下Cookie的其他屬性,再刪除,看能否把Cookie刪除掉
//一定不要忘記添加到瀏覽器中 cookie.setPath("/ouzicheng"); cookie.setMaxAge(0); response.addCookie(cookie); printWriter.write("刪除一個Cookie");
結果Cookie還在硬盤中
Cookie的域名Cookie的domain屬性決定運行訪問Cookie的域名。domain的值規定為“.域名”
Cookie的隱私安全機制決定Cookie是不可跨域名的。也就是說www.baidu.com和www.google.com之間的Cookie是互不交接的。即使是同一級域名,不同二級域名也不能交接,也就是說:www.goole.com和www.image.goole.com的Cookie也不能訪問
我在本地上配置了3個虛擬主機,localhost,www.zhongfucheng.com,www.image.zhongfucheng.com【如果不知道怎么配置,在我Tomcat的博客有】
我用www.zhongfucheng.com域名發送了一個Cookie給瀏覽器
Cookie cookie = new Cookie("name", "zhongfucheng"); cookie.setMaxAge(1000); response.addCookie(cookie); printWriter.write("使用www.zhongfucheng.com域名添加了一個Cookie");
首先,證明了Cookie不可跨名性,localhost域名拿不到www.zhongfucheng.com頒發給瀏覽器的Cookie
再使用www.image.zhongfucheng.com域名訪問,證明即使一級域名相同,二級域名不同,也不能獲取到Cookie
當然,使用www.zhongfucheng.com當然能獲取到Cookie,Cookie通過請求頭帶給服務器
現在我希望一級域名相同的網頁Cookie之間可以相互訪問。也就是說www.image.zhongfucheng.com可以獲取到www.zhongfucheng.com的Cookie就需要使用到domain方法。
Cookie cookie = new Cookie("name", "ouzicheng"); cookie.setMaxAge(1000); cookie.setDomain(".zhongfucheng.com"); response.addCookie(cookie); printWriter.write("使用www.zhongfucheng.com域名添加了一個Cookie,只要一級是zhongfucheng.com即可訪問");
使用www.zhongfucheng.com發布一個Cookie
使用www.image.zhongfucheng.com域名訪問一下。發現可以獲取到Cookie了
Cookie的路徑Cookie的path屬性決定允許訪問Cookie的路徑
一般地,Cookie發布出來,整個網頁的資源都可以使用。現在我只想Servlet1可以獲取到Cookie,其他的資源不能獲取。
使用Servlet2頒發一個Cookie給瀏覽器,設置路徑為"/Servlet1"。
Cookie cookie = new Cookie("username", "java"); cookie.setPath("/Servlet1"); cookie.setMaxAge(1000); response.addCookie(cookie); printWriter.write("該Cookie只有Servlet1獲取得到");
使用Servlet3訪問服務器,看看瀏覽器是否把Cookie帶上。顯然,瀏覽器訪問Servlet3并沒有把Cookie帶上。
使用Servlet1訪問服務器,看看瀏覽器是否把Cookie帶上。答案是肯定的!
Cookie的安全屬性HTTP協議不僅僅是無狀態的,而且是不安全的!如果不希望Cookie在非安全協議中傳輸,可以設置Cookie的secure屬性為true,瀏覽器只會在HTTPS和SSL等安全協議中傳輸該Cookie。
當然了,設置secure屬性不會將Cookie的內容加密。如果想要保證安全,最好使用md5算法加密【后面有】。
Cookie的應用 顯示用戶上次訪問的時間其實就是每次登陸的時候,取到Cookie保存的值,再更新下Cookie的值。
訪問Serlvet有兩種情況
第一次訪問
已經訪問過了
全部代碼如下:
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); response.setContentType("text/html;charset=UTF-8"); PrintWriter printWriter = response.getWriter(); //獲取網頁上所有的Cookie Cookie[] cookies = request.getCookies(); //判斷Cookie的值是否為空 String cookieValue = null; for (int i = 0; cookies != null && i < cookies.length; i++) { //獲取到以time為名的Cookie if (cookies[i].getName().equals("time")) { printWriter.write("您上次登陸的時間是:"); cookieValue = cookies[i].getValue(); printWriter.write(cookieValue); cookies[i].setValue(simpleDateFormat.format(new Date())); response.addCookie(cookies[i]); //既然已經找到了就可以break循環了 break; } } //如果Cookie的值是空的,那么就是第一次訪問 if (cookieValue == null) { //創建一個Cookie對象,日期為當前時間 Cookie cookie = new Cookie("time", simpleDateFormat.format(new Date())); //設置Cookie的生命期 cookie.setMaxAge(20000); //response對象回送Cookie給瀏覽器 response.addCookie(cookie); printWriter.write("您是第一次登陸啊!"); }
按照正常的邏輯來寫,程序流程應該是這樣子的。先創建Cookie對象,回送Cookie給瀏覽器。再遍歷Cookie,更新Cookie的值。
但是,按照上面的邏輯是做不到的!因為每次訪問Servlet的時候都會覆蓋原來的Cookie,取到Cookie的值永遠都是當前時間,而不是上次保存的時間。
我們換一個邏輯寫:先檢查(遍歷)所有Cookie有沒有我要的,如果得不到我想要的Cookie,Cookie的值是null,那么就是第一次登陸,于是就有了上面的代碼了。
我們來看下效果吧!當我第一次登陸的時候
Cookie保存在硬盤中。
再次訪問Servlet。明顯地,取到的就是Cookie的值
顯示上次瀏覽過商品我就以書籍為例子了!首先設計Book對象
private String id ; private String name ; private String author; public Book() { } public Book(String id, String name, String author) { this.id = id; this.name = name; this.author = author; } ...各種set、get方法
設計一個簡單的數據庫存儲數據。就用LinkedHashMap集合【根據商品的id找書籍所以用Map,刪改較多所以用Linked】
private static LinkedHashMaplinkedHashMap = new LinkedHashMap(); //簡化開發復雜度,book的id和商品的id相同 static { linkedHashMap.put("1", new Book("1", "javaweb", "zhong")); linkedHashMap.put("2", new Book("2", "java", "fu")); linkedHashMap.put("3", new Book("3", "oracle", "cheng")); linkedHashMap.put("4", new Book("4", "mysql", "ou")); linkedHashMap.put("5", new Book("5", "ajax", "zi")); } //獲取到所有書籍 public static LinkedHashMap getAll() { return linkedHashMap; }
顯示網頁上所有的書籍【首頁】
printWriter.write("網頁上所有的書籍:"+"
"); //拿到數據庫所有的書 LinkedHashMaplinkedHashMap = DB.getAll(); Set > entry = linkedHashMap.entrySet(); //顯示所有的書到網頁上 for (Map.Entry stringBookEntry : entry) { Book book = stringBookEntry.getValue(); printWriter.write(book.getId() +" "+ book.getName()+"
"); }
接著,我們要做的就是給顯示的書籍掛上一個超鏈接,當用戶點擊想看的書籍時,就跳轉到該書籍的詳細信息頁面
超鏈接應該把書的id傳遞過去,不然處理頁面是不知道用戶想看的是哪一本書的!
//顯示所有的書到網頁上 for (Map.EntrystringBookEntry : entry) { Book book = stringBookEntry.getValue(); printWriter.write(""); printWriter.write("
"); }
接收id,找到用戶想要看哪一本書,輸出該書的詳細信息
String id = request.getParameter("id"); //由于book的id和商品的id是一致的。獲取到用戶點擊的書 Book book = (Book) DB.getAll().get(id); //輸出書的詳細信息 printWriter.write("書的編號是:" + book.getId()+"
"); printWriter.write("書的名稱是:" + book.getName()+"
"); printWriter.write("書的作者是:" + book.getAuthor()+"
");
點擊想要的書籍。
得到書籍的詳細信息
既然用戶點擊了書籍,那么服務器就應該頒發Cookie給瀏覽器,記住用戶點擊了該書籍
現在問題來了,Cookie的值應該是什么呢?試想一下,待會還要把瀏覽過的書籍顯示出來,所以用書籍的id是最好不過的。想到了用書籍的id作為Cookie的值,我們還要定義一些規則!
我們可能有非常多的書籍,不可能把用戶瀏覽過的書籍都顯示出來。所以我們定義只能顯示3本瀏覽過的書籍
書籍的id都是數字,如果不做任何修改,存到Cookie里邊可能就是231,345,123此類的數字,這樣取出某一個id的時候就十分費勁并且后面還要判斷該書是否存在Cookie里邊了,所以我們要把存儲到Cookie的書籍id分割起來。所以我們定義”_“作為分隔符
按上面的應用,我們的邏輯應該是:先遍歷下Cookie,看下有沒有我們想要的Cookie。如果找到想要的Cookie,那就取出Cookie的值
String bookHistory = null; Cookie[] cookies = request.getCookies(); for (int i = 0; cookies != null && i < cookies.length; i++) { if (cookies[i].getName().equals("bookHistory")) { bookHistory = cookies[i].getValue(); } }
取出了Cookie的值也分幾種情況
Cookie的值為null【直接把傳入進來的id當做是Cookie的值】
Cookie的值長度有3個了【把排在最后的id去掉,把傳進來的id排在最前邊】
Cookie的值已經包含有傳遞進來的id了【把已經包含的id先去掉,再把id排在最前面】
Cookie的值就只有1個或2個,直接把id排在最前邊
if (bookHistory == null) { return id; } //如果Cookie的值不是null的,那么就分解Cookie的得到之前的id。 String[] strings = bookHistory.split("\_"); //為了增刪容易并且還要判斷id是否存在于該字符串內-----我們使用LinkedList集合裝載分解出來的id List list = Arrays.asList(strings); LinkedListlinkedList = new LinkedList<>(); linkedList.addAll(list); if (linkedList.contains(id)) { linkedList.remove(id); linkedList.addFirst(id); }else { if (linkedList.size() >= 3) { linkedList.removeLast(); linkedList.addFirst(id); } else { linkedList.addFirst(id); } }
這么折騰完了,我們的Cookie值就在LinkedList集合里邊了。接下來,我們要做的就是把集合中的值取出來,拼接成一個字符串
StringBuffer stringBuffer = new StringBuffer(); //遍歷LinkedList集合,添加個下劃線“_” for (String s : linkedList) { stringBuffer.append(s + "_"); } //最后一個元素后面就不需要下劃線了 return stringBuffer.deleteCharAt(stringBuffer.length() - 1).toString();
好的,我們現在已經完成了Cookie值了。接下來設置Cookie的生命周期,回送給瀏覽器即可
String bookHistory = makeHistory(request, id); Cookie cookie = new Cookie("bookHistory", bookHistory); cookie.setMaxAge(30000); response.addCookie(cookie);
既然我們已經把Cookie回送給瀏覽器了。那么接下來我們就在首頁上獲取Cookie的值,顯示用戶瀏覽過什么商品就行了!
printWriter.write("您曾經瀏覽過的商品:"); printWriter.write("
"); //顯示用戶瀏覽過的商品 Cookie[] cookies = request.getCookies(); for (int i = 0; cookies != null && i < cookies.length; i++) { if (cookies[i].getName().equals("bookHistory")) { //獲取到的bookHistory是2_3_1之類的 String bookHistory = cookies[i].getValue(); //拆解成每一個id值 String[] ids = bookHistory.split("\_"); //得到每一個id值 for (String id : ids) { //通過id找到每一本書 Book book = linkedHashMap.get(id); printWriter.write(book.getName()); printWriter.write("
"); } break; } }
好的,我們來試驗一下吧!!,第一次訪問首頁,并沒有瀏覽過的商品
當我點擊javaweb書籍再訪問首頁的時候
再點擊ajax然后訪問首頁
再點擊javaweb然后訪問首頁
點擊oracle然后訪問首頁
好的,經過測試,該程序應該沒有什么問題了!
如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章的同學,可以關注微信公眾號:Java3y
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/68435.html
摘要:前言由于寫的文章已經是有點多了,為了自己和大家的檢索方便,于是我就做了這么一個博客導航。 前言 由于寫的文章已經是有點多了,為了自己和大家的檢索方便,于是我就做了這么一個博客導航。 由于更新比較頻繁,因此隔一段時間才會更新目錄導航哦~想要獲取最新原創的技術文章歡迎關注我的公眾號:Java3y Java3y文章目錄導航 Java基礎 泛型就這么簡單 注解就這么簡單 Druid數據庫連接池...
摘要:協議是無狀態的,一旦數據交換完畢,客戶端與服務器端的連接就會關閉,再次交換建立新的連接,也就是說,服務器無法跟蹤會話。而和就是用與解決這種問題。值得一提的是是建立在的基礎上創建的。注意在的文件中,設置了的生命周期最長為分鐘。 在將cookie 和 session 之前需要先理解什么是會話會話: 用戶打開一個瀏覽器,點擊多個超鏈接,訪問多個web資源,然后關閉瀏覽器,整個過程稱為一個...
摘要:標簽在為一個地址附加參數時,將自動對參數值進行編碼,例如,如果傳遞的參數值為中國,則將其轉換為后再附加到地址后面,這也就是使用標簽的最大好處。 什么是JSTL JSTL全稱為 JSP Standard Tag Library 即JSP標準標簽庫。 JSTL作為最基本的標簽庫,提供了一系列的JSP標簽,實現了基本的功能:集合的遍歷、數據的輸出、字符串的處理、數據的格式化等等! 為什么要使...
閱讀 2747·2021-09-24 09:47
閱讀 4375·2021-08-27 13:10
閱讀 2990·2019-08-30 15:44
閱讀 1289·2019-08-29 12:56
閱讀 2598·2019-08-28 18:07
閱讀 2619·2019-08-26 14:05
閱讀 2569·2019-08-26 13:41
閱讀 1271·2019-08-26 13:33