session及cookies理解(結(jié)合購物車和用戶登錄案例)

總結(jié):

以下幾個案例難點在于:
a、什么時候需要創(chuàng)建session荚藻,什么時候只是讀任莨唷(涉及getsession方法的參數(shù)),還需要了解一下getsession方法是如何實現(xiàn)的应狱,為什么好像沒有訪問cookies就得到了session共郭。
b、什么時候要向瀏覽器發(fā)送cookies,使用哪個Servlet向瀏覽器發(fā)送cookies落塑。

(注:由于案例比較簡單纽疟,更多是起示范作用,所以很少引入html頁面和表單憾赁,很多時候是直接通過在瀏覽器地址欄輸入URL來直接訪問Servlet)污朽。


案例1:(cookie案例)——顯示用戶上次訪問時間

??該案例要實現(xiàn)的是當(dāng)用戶訪問某些web應(yīng)用時,顯示出上次的訪問時間龙考。
??該案例只用到一個LastAccessServlet蟆肆,并且不需要多余的頁面(例如表單),結(jié)果也是直接通過字符流打印出來顯示在瀏覽器上晦款。通過localhost/chapter06/LastAccessServlet來進行訪問炎功。(其中chapter06該案例對應(yīng)的應(yīng)用的名稱,而/LastAccessServlet會跳轉(zhuǎn)到LastAccessServlet這個類)
??接下來缓溅,request會獲取cookies中name為lastAccessTime的cookie蛇损,首先request請求先獲取cookies。這時候會有cookies為空和非空兩種可能性坛怪。只有cookies非空我們才對它進行遍歷淤齐,如果能找到name為LastAccessTime的cookie,那么我們就獲取它的值袜匿,如果遍歷完成還沒找到更啄,或者本身cookies就為空,這兩種情況我們都歸納為lastAccessTime== null居灯,在該條件下在瀏覽器返回“首次訪問本站”的信息祭务。否則就將LastAccessTime的值顯示出來。

//  LastAccessServlet類doGet方法中的部分代碼,request代表HttpServletRequest請求怪嫌。
String lastAccessTime = null;
Cookie[] cookies = request.getCookies();
for (int i=0;cookies != null && i<cookies.length;i++){
    if("lastAccess".equals(cookies[i].getName())){
        lastAccessTime = cookies[i].getValue();
        break;
    }
}
if(lastAccessTime == null){...//返回首次訪問本站信息
}else{
    ...//返回上次訪問時間
}

??這一切結(jié)束后义锥,再將lastAccess賦值為當(dāng)前時間,然后通過HttpServletResponse對象將其添加到cookie中岩灭。

String currenttime = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());
response.addCookie(cookie);

案例2(session案例)——實現(xiàn)購物車

??這里的購物車只是一個比較簡單的模型缨该,沒有涉及數(shù)據(jù)庫的內(nèi)容。用一個BookDB.java來模擬保存所有圖書(定義為Book類)的數(shù)據(jù)庫川背,說的直白一些贰拿,就是在BookDB里面定義了一個Map集合(之所以在這里使用集合而不使用數(shù)組,一是因為可以增刪熄云,長度不固定膨更,二是這里保存的是鍵值對。鍵(id)在后續(xù)中用于實現(xiàn)查詢功能缴允。而在 purchaseServlet中荚守,由于只需要遍歷而不需要查詢珍德,所以使用的是ArrayList)鍵(id)的查詢功能包括兩個:一是根據(jù)指定的id來獲得一個圖書對象矗漾。這個功能本質(zhì)上是通過Map集合的get(Object key)方法來實現(xiàn)锈候,返回Object類型。二是獲取所有的圖書對象集合敞贡,這個功能通過Map集合的values()方法實現(xiàn)泵琳,返回Collection<V> 類型。這個集合里面的一個元素由序號和Book組成誊役。

public class BookDB {
private static Map<String, Book> books = new LinkedHashMap<String, Book>();
static {
    books.put("1", new Book("1", "javaweb開發(fā)"));
    ......
    books.put("5", new Book("5", "spring開發(fā)"));
    }
// 獲得所有的圖書
    public static Collection<Book> getAll() {
        return books.values();
    }
// 根據(jù)指定的id獲得圖書
    public static Book getBook(String id) {
        return books.get(id);
    }
}

??不同的對象就好像象棋中不同的棋子(例如車馬象)获列,有不同的“走法”(方法)。我們當(dāng)然都希望他們能夠橫豎甚至對角線都能走蛔垢,但是做不到击孩。 每個對象都有它們自己特定的方法這里除了request和response對象以外,還需要引入ListBookServlet鹏漆、PurchaseServlet和CartServlet巩梢。
需要的Servlet的多少是根據(jù)我們的業(yè)務(wù)需求來決定的

購物車的實現(xiàn)流程圖

??第一個需求就是訪問某個Servlet(這里是ListBookServlet)列出我們的所有“可購買書單”艺玲。上面說過括蝠,列出所有書單的功能Map的values()方法已經(jīng)能夠?qū)崿F(xiàn)(甚至直接BookDB類就可以觸發(fā)方法,而不需要實例化)板驳,而response對象能將其遍歷的結(jié)果通過輸出流顯示到瀏覽器上又跛。而ListBookServlet除了實現(xiàn)這兩個基本的功能碍拆,還在輸出結(jié)果時若治,在遍歷的每個條目的后面添加一個購買鏈接(顯示為“點擊購買”字樣)。一旦我們點擊了鏈接感混,就會跳轉(zhuǎn)到PurchaseServlet端幼,同時還會帶上一個id參數(shù)(這部分代碼如下所示)。到這里弧满,第一個Servlet(ListsBookServlet)的功能就結(jié)束了婆跑。

    for (Book book : books) {
        String url = "/chapter06/PurchaseServlet?id=" + book.getId();
        out.write(book.getName() + "<a href='" + url 
                + "'>點擊購買</a><br>");
    }

??接著我們的PurchaseServlet出場了,他面對的是一個新的請求庭呜,這個請求是從ListBookServlet跳轉(zhuǎn)而來滑进,后面帶有一個id參數(shù)。如果沒有這個id募谎,表示可能直接由瀏覽器輸入localhost:/chapter06/PurchaseServlet發(fā)起的請求扶关,這時候就需要重定向回到 ListBookServlet,這么做是確保我們的PurchaseServlet面對的請求帶有id這個參數(shù)数冬。

??當(dāng)存在id參數(shù)時节槐,表明已經(jīng)有用戶點擊購買。這時候通過getSession()方法(手動)獲取或者創(chuàng)建一個HttpSession對象,這個session用于存放我們的信息铜异。
request.getSession()方法等同于request.getSession(True)哥倔,它意味著能夠在Httpsession對象不存在時創(chuàng)建新的session對象。
注:這時候如果沒有session服務(wù)器是需要創(chuàng)建session的揍庄。因為我們需要session來存放這個購買請求咆蒿。所以我們使用的是getSession(True)而不是getSession(False)方法。

??至于為什么來自客戶端的request調(diào)用getSession方法就可以訪問到服務(wù)端的session信息币绩。我的理解是request(包裝后的 HttpServlet對象)先查詢自己的cookies蜡秽,根據(jù)cookies中的session關(guān)聯(lián)id獲取到存放于服務(wù)器中的session對象。
??session的關(guān)聯(lián)號存放于cookies中缆镣,而cookies存放于瀏覽器端芽突,在發(fā)起特定請求后可以理解為cookies信息被封裝到 request對象中,所以通過request.getSession()方法可以獲取cookies中的session關(guān)聯(lián)號董瞻,再據(jù)此找到對應(yīng)的session寞蚌。
??當(dāng)我們在瀏覽器地址欄中直接訪問cartServlet,想讀取已購買數(shù)目信息钠糊,我們的服務(wù)器就需要讀取session挟秤,所以在cartServlet之前,也即是PurchaseServlet這里就應(yīng)該發(fā)送cookies到客戶端了抄伍。
??而在案例3中艘刚,我們會直接訪問login.html,并且這個請求同樣需要讀取對應(yīng)的 session截珍,所以我們應(yīng)該在login.html之前攀甚,也就是indexServlet這里,將我們的cookies發(fā)回給瀏覽器岗喉。只有這樣秋度,當(dāng)我們直接訪問時,才能夠通過getSession()方法來找到對應(yīng)的session對象钱床。

??session有兩個比較常用的方法荚斯,一個是getAttribute(),用于返回session中指定名稱的屬性對象查牌。另外一個是getID事期,用于返回與當(dāng)前HttpSession對象關(guān)聯(lián)的會話標(biāo)識號。
??在purchaseServlet中只需要一個ArrayList(而不用 Map)來存儲cart(購物車)的值就可以了纸颜。

    List<Book> cart = (List) session.getAttribute("cart");
    if (cart == null) {
        // 首次購買兽泣,為用戶創(chuàng)建一個購物車(List集合模擬購物車)
        cart = new ArrayList<Book>();
        // 將購物城存入Session對象
        session.setAttribute("cart", cart);
    }
    // 將商品放入購物車
    cart.add(book);

??然后創(chuàng)建cookie用于存放session的標(biāo)識號。并且這時候其實purchaseServlet沒有向用戶顯示任何的信息懂衩,只是進行了一些后臺的操作撞叨,然后繼續(xù)跳轉(zhuǎn)到CartServlet金踪。
CartServlet先獲得用戶的session.

HttpSession session = req.getSession(false);

??這里使用 false表明如果當(dāng)前沒有session存在,那么session = null牵敷,而不會繼續(xù)新建一個session對象胡岔。 最終是想要讀取session中名為“cart”的ArrayList集合。并通過字符流將book對象的名字打印出來枷餐。
??那么為什么不將CartServlet和purchaseServlet結(jié)合在一起呢靶瘸。
這里需要搞清楚這個案例的意義,在這個案例中毛肋,用戶直接訪問/ListBookServlet進行購買(當(dāng)我們點擊購買鏈接以后就在瀏覽器上顯示我們已經(jīng)購買了這本書)怨咪,而直接訪問cartServlet用于查看已經(jīng)購買的書。想要重新購買新的書時润匙,需要再次訪問/ListBookServlet來進行購買诗眨。如果將PurchaseServlet和CartServlet結(jié)合在一起。就沒有辦法制作出不帶session的訪問請求了孕讳。而現(xiàn)在匠楚,在請求跳轉(zhuǎn)到CartServlet前,已經(jīng)將帶有session標(biāo)識號的cookie發(fā)送到客戶端了厂财,這時候無論是從哪里再跳轉(zhuǎn)到Servlet芋簿,都可以訪問到session了。在應(yīng)用中跳轉(zhuǎn)過去的可以璃饱,直接從瀏覽器地址欄訪問的也可以与斤。但是手動刪除瀏覽器的cookies,那么再直接訪問就訪問不到session了荚恶。


案例3(session案例)——實現(xiàn)用戶登錄

回顧文章開頭提出的兩個難點:
a撩穿、什么時候創(chuàng)建session,什么時候只是讀锐伤Α(getsession方法)
b冗锁、什么時候要向瀏覽器發(fā)送cookies齐唆。

??可以這樣理解嗤栓,如果訪問時需要這些session信息,例如通過瀏覽器訪問Login.html時要想成功登錄箍邮,就需要讀取session信息茉帅,那么就需要在這之前提前發(fā)送cookies。所以在這個案例中锭弊,我們是在indexServlet中發(fā)送cookies信息堪澎。而在前面的案例中,我們希望直接訪問cartServlet來讀取我們當(dāng)前購買了什么書味滞,那么在這個cartServlet之前就必須要將cookies傳送完畢樱蛤。

??其實從流程圖就可以看出來钮呀,loginservlet和logoutservlet都是會連接到我們的indexservlet的。loginservlet的作用是將表單的內(nèi)容創(chuàng)建成為一個user對象保存到session中昨凡。而logoutservlet則是將我們的user對象從session中進行刪除爽醋。然后indexservlet先從服務(wù)器中讀取我們的session,如果有就登錄成功便脊,沒有就跳轉(zhuǎn)到登錄頁面蚂四。并且只有當(dāng)存在對象的時候,才會將我們的session使用 getid的方法保存到cookie中哪痰。

能不能在loginServlet中發(fā)送cookies遂赠?

??loginservlet還能通過“注銷”按鈕跳轉(zhuǎn)到logoutservlet,當(dāng)我們登錄跳轉(zhuǎn)到loginservlet晌杰,如果用戶信息驗證通過就發(fā)送cookies的話跷睦,這時候再注銷,session里面的對象就沒有了肋演,但是cookies卻已經(jīng)發(fā)出去了送讲。那么我們再次訪問時,cookies里面的內(nèi)容就對不上了惋啃。這樣的邏輯容易混亂哼鬓。

能不能實現(xiàn)用戶自動登錄功能?

??這里只是實現(xiàn)了用戶登錄功能边灭,并沒有實現(xiàn)用戶自動登錄功能异希。原因在于該案例中用戶想要登錄時都必須經(jīng)過Login.html,然后再經(jīng)過LoginServlet驗證绒瘦。也就是說称簿,雖然我們的indexServlet已經(jīng)將cookies發(fā)送到瀏覽器端。但是用戶想登錄還是要老老實實通過Login.html惰帽,如果能夠?qū)⑷魏我粋€請求都繞過Login.html憨降,直接跳轉(zhuǎn)到LoginServlet進行驗證,如果通過的話不就能實現(xiàn)自動登錄了嗎该酗?Filter就可以用來實現(xiàn)這樣的功能授药。

??在Filter實現(xiàn)用戶自動登錄的案例中,可以看到呜魄,AutoLoginFilter中同樣有LoginServlet中一樣的用于驗證用戶信息的代碼(其實就相當(dāng)于這里提出的跳轉(zhuǎn)到LoginServlet的思路)悔叽。另外,F(xiàn)ilter案例中沒有IndexServlet爵嗅,所以發(fā)送cookie的代碼在loginServlet和LogoutServlet中都要有娇澎。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末重绷,一起剝皮案震驚了整個濱河市益缎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖伙菊,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件募舟,死亡現(xiàn)場離奇詭異窘俺,居然都是意外死亡遇八,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門虑鼎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辱匿,“玉大人,你說我怎么就攤上這事炫彩∝移撸” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵江兢,是天一觀的道長昨忆。 經(jīng)常有香客問我,道長杉允,這世上最難降的妖魔是什么邑贴? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮叔磷,結(jié)果婚禮上拢驾,老公的妹妹穿的比我還像新娘。我一直安慰自己改基,他們只是感情好繁疤,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著秕狰,像睡著了一般稠腊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鸣哀,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天架忌,我揣著相機與錄音,去河邊找鬼我衬。 笑死叹放,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的低飒。 我是一名探鬼主播许昨,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼懂盐,長吁一口氣:“原來是場噩夢啊……” “哼褥赊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起莉恼,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤拌喉,失蹤者是張志新(化名)和其女友劉穎速那,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體尿背,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡端仰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了田藐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荔烧。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖汽久,靈堂內(nèi)的尸體忽然破棺而出鹤竭,到底是詐尸還是另有隱情,我是刑警寧澤景醇,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布臀稚,位于F島的核電站,受9級特大地震影響三痰,放射性物質(zhì)發(fā)生泄漏吧寺。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一散劫、第九天 我趴在偏房一處隱蔽的房頂上張望稚机。 院中可真熱鬧,春花似錦获搏、人聲如沸抒钱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谋币。三九已至,卻和暖如春症概,著一層夾襖步出監(jiān)牢的瞬間蕾额,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工彼城, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留诅蝶,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓募壕,卻偏偏與公主長得像调炬,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子舱馅,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 會話(Session)跟蹤是Web程序中常用的技術(shù)缰泡,用來跟蹤用戶的整個會話。常用的會話跟蹤技術(shù)是Cookie與Se...
    chinariver閱讀 5,617評論 1 49
  • 目錄Cookie機制什么是CookieCookie的不可跨域名性Unicode編碼:保存中文BASE64編碼:保存...
    Tomatoro閱讀 16,942評論 7 186
  • 從三月份找實習(xí)到現(xiàn)在代嗤,面了一些公司棘钞,掛了不少缠借,但最終還是拿到小米、百度宜猜、阿里泼返、京東、新浪姨拥、CVTE绅喉、樂視家的研發(fā)崗...
    時芥藍閱讀 42,246評論 11 349
  • 夢境: 跟著一個男的假裝去見家長,然后他媽媽又是夾菜又是塞錢的叫乌,好到不好意思…… 單詞15 看書:《所羅門...
    是魔王大人閱讀 191評論 5 0
  • 6月21日霹疫,夏至節(jié)氣,一大早四點就起床去鏡湖拍日出综芥,結(jié)果剛剛霞光微露就蹤影全無丽蝎, 幸好濕地深處荷花綻放,就隨手拍幾...
    我愛蘋果絲閱讀 440評論 2 1