Session
Cookie技術(shù)可以將用戶的信息保存在各自的瀏覽器中宁炫,
優(yōu)點(diǎn):很明顯實(shí)現(xiàn)了同一個(gè)用戶不同請(qǐng)求中數(shù)據(jù)共享簇抵。
缺點(diǎn):黑客可以利用腳本等手段 竊取cookie中的重要數(shù)據(jù)喇完,從而泄漏個(gè)人的隱私,存在巨大的安全隱患逛球。
session技術(shù) 是將會(huì)話的數(shù)據(jù)保存在服務(wù)器端的技術(shù)柿祈。
3.1.什么是session绑莺?
為了更好的理解session暖眼,以網(wǎng)站購(gòu)物為例,通過(guò)一張圖來(lái)描述session保存用戶 信息的原理纺裁。
用戶甲和用戶乙都調(diào)用buyServlet將商品添加到購(gòu)物車诫肠,調(diào)用payServlet進(jìn)行商品結(jié)算。
由于甲和乙購(gòu)買商品類似,這里以甲為主区赵。
當(dāng)用戶甲訪問購(gòu)物網(wǎng)站時(shí)杜跷,服務(wù)器為甲創(chuàng)建了一個(gè)session對(duì)象(相當(dāng)于購(gòu)物車)页徐。
當(dāng)甲將小米手機(jī)添加到購(gòu)物車時(shí)浅役,小米手機(jī)的信息便存到了session對(duì)象中媳危,同時(shí),服務(wù)器將session對(duì)象的唯一標(biāo)識(shí)id屬性以Cookie的形式返回給甲的瀏覽器骡送。
當(dāng)甲完成購(gòu)物進(jìn)行結(jié)賬時(shí)昂羡,需要向服務(wù)器結(jié)賬請(qǐng)求,這時(shí)摔踱,瀏覽器就會(huì)自動(dòng)在請(qǐng)求頭將 唯一標(biāo)識(shí) 回送給服務(wù)器虐先。
服務(wù)器根據(jù)唯一標(biāo)識(shí),找到為用戶甲創(chuàng)建的session容器派敷,并將session對(duì)象中存放的手機(jī)信息進(jìn)行結(jié)算蛹批。
需要注意的是:由于客戶端需要接受、記錄篮愉、和回送session的唯一標(biāo)識(shí)腐芍,
因此通常情況下,session是借助cookie技術(shù)來(lái)傳遞ID屬性的试躏。
3.1.Session的API
3.1.1.獲取Session對(duì)象
Session是基于用戶的請(qǐng)求猪勇,而把用戶的重要信息在服務(wù)器端針對(duì)這個(gè)用戶(瀏覽器)創(chuàng)建了一個(gè)容器。
而這個(gè)Session容器是由web服務(wù)器(tomcat)幫助我們創(chuàng)建的颠蕴,在程序中我們只能去獲取到這個(gè)容器泣刹,然后給容器添加數(shù)據(jù)或者取出數(shù)據(jù),或者刪除數(shù)據(jù)犀被,而我們是不能創(chuàng)建這個(gè)容器對(duì)象椅您。
在HttpServletRequest對(duì)象中提供了獲取session對(duì)象的方法:
使用request對(duì)象就可以獲取到當(dāng)前針對(duì)用戶的請(qǐng)求服務(wù)器內(nèi)部創(chuàng)建的那個(gè)Session容器對(duì)象。
HttpSession依然是一個(gè)接口寡键,而這個(gè)接口的實(shí)現(xiàn)類有web服務(wù)器來(lái)提供掀泳。只要能夠運(yùn)行我們JavaEE項(xiàng)目的web訪問前,它們都會(huì)實(shí)現(xiàn)Java提供的所有web技術(shù)中的接口昌腰。
演示Session:
需要2個(gè)Servlet程序:
在第一個(gè)Servlet中獲取到Session對(duì)象,然后把用戶當(dāng)前的ip保存在Session中膀跌,在第二Servlet中取出遭商,然后通過(guò)response對(duì)象把ip給客戶端響應(yīng)回去。第一個(gè)Servlet訪問完之后捅伤,不使用轉(zhuǎn)發(fā)技術(shù)劫流。
給Session對(duì)象中保存數(shù)據(jù):
需要使用HttpSession接口中的:
獲取數(shù)據(jù):
刪除Session中的數(shù)據(jù)
需求1: 共享數(shù)據(jù):第一個(gè)Servlet程序:獲取到用戶的ip保存在Session中;在第二個(gè)servlet中取出session中的ip(debug演示)
3、新建Session2Servlet祠汇,從session中獲取ip
4仍秤、通過(guò)瀏覽器直接訪問Session2Servlet,能夠看到ip嗎可很?
看不到诗力,原因:還沒有向session容器中存放ip。
5我抠、通過(guò)瀏覽器先訪問Session1Servlet苇本,再訪問Session2Servlet,能看到ip地址嗎菜拓? 能
3.2.2.服務(wù)器端操作Session時(shí)細(xì)節(jié)
其實(shí)服務(wù)器端可以識(shí)別每個(gè)用戶的對(duì)應(yīng)的Session容器瓣窄,主要是因?yàn)榉?wù)器針對(duì)每個(gè)用戶都發(fā)送了JSESSIONID(session容器的唯一標(biāo)識(shí))的Cookie信息。這樣用戶在操作的時(shí)候纳鼎,都會(huì)攜帶這個(gè)Cookie到服務(wù)器端俺夕,因此服務(wù)器端才能識(shí)別針對(duì)當(dāng)前這個(gè)用戶的那個(gè)session容器對(duì)象。
服務(wù)器在給客戶端響應(yīng)數(shù)據(jù)的時(shí)候贱鄙,把Session容器的唯一標(biāo)識(shí)以Cookie的形式發(fā)送給瀏覽器劝贸,而這個(gè)Cookie是一個(gè)會(huì)話級(jí)別(臨時(shí))Cookie,它只能存活在瀏覽器運(yùn)行的階段贰逾,如果瀏覽器關(guān)閉了悬荣,這個(gè)Cookie信息就沒有了,因此在此打開瀏覽器訪問的時(shí)候疙剑,就不會(huì)在服務(wù)器獲取到針對(duì)當(dāng)前用戶的JSESSIONID信息氯迂,因此無(wú)法找到針對(duì)當(dāng)前用戶的那個(gè)Session容器。
進(jìn)一步說(shuō)明言缤,服務(wù)器端的Session容器對(duì)象嚼蚀,是針對(duì)每個(gè)瀏覽器的。
3.2.3.使用getSession方法的細(xì)節(jié)
在api中提供2個(gè)獲取Session對(duì)象的方法:
getSession():
空參數(shù)的方法管挟,在使用的時(shí)候轿曙,如果服務(wù)器端針對(duì)當(dāng)前用戶的瀏覽器沒有Session容器,這時(shí)在服務(wù)器的內(nèi)部會(huì)先創(chuàng)建一個(gè)Session對(duì)象僻孝,然后把這個(gè)Session對(duì)象返回給我們的程序导帝。
如果Session容易已經(jīng)存在,這時(shí)它是不會(huì)再創(chuàng)建新的Session容器對(duì)象穿铆,只是把找到的這個(gè)Session容器對(duì)象返回給程序您单。在找的過(guò)程中需要依賴于JSESSIONID。
getSession(Boolean create):
如果這個(gè)在調(diào)用的時(shí)候荞雏,傳遞的值為false虐秦,它僅僅只會(huì)在容器根據(jù)JSESSIONID找有沒有對(duì)應(yīng)的Session容器對(duì)象平酿,如果有就返回這個(gè)Session容器對(duì)象,如果沒有悦陋,就返回null蜈彼。
如果傳遞的值true,在根據(jù)JSESSIONID找Session容器對(duì)象的時(shí)候俺驶,如果不存在就會(huì)創(chuàng)建一個(gè)新的Session容器對(duì)象幸逆,并返回這個(gè)容器對(duì)象,如果存在就痒钝,直接返回存在的Session容器對(duì)象秉颗。
3.3.思考:關(guān)閉瀏覽器后再次訪問能獲取到Session的數(shù)據(jù)嗎?
一般情況下送矩,關(guān)閉瀏覽器之后蚕甥,再次訪問,是無(wú)法獲取到Session中的數(shù)據(jù)的栋荸。
因此在服務(wù)器針對(duì)當(dāng)前用戶的第一次請(qǐng)求創(chuàng)建的唯一的Session容器對(duì)象菇怀,而在給這次請(qǐng)求的之后,服務(wù)器需要給用戶響應(yīng)數(shù)據(jù)晌块,在響應(yīng)的時(shí)候爱沟,服務(wù)器把當(dāng)前Session容器對(duì)象的JSESSIONID以Cookie的形式發(fā)送給了瀏覽器。而這個(gè)Cookie并沒有設(shè)置有效時(shí)間匆背,那么這個(gè)Cookie就屬于臨時(shí)Cookie呼伸,在關(guān)閉瀏覽器之后,再次打開瀏覽器的時(shí)候钝尸,上次的Cookie已經(jīng)消失了括享,用戶雖然拿同一個(gè)瀏覽器訪問服務(wù)器,可是這時(shí)沒有JSESSIONID珍促,服務(wù)器端的Session容器依然存在铃辖,但是沒有JSESSIONID,服務(wù)器內(nèi)部無(wú)法獲取到這個(gè)session對(duì)象
把包含了JSESSIONID的Cookie在客戶端持久化猪叙。
3.4.禁用Cookie后Session追蹤
服務(wù)器端獲取Session對(duì)象依賴于客戶端攜帶的Cookie中的JSESSIONID數(shù)據(jù)娇斩。如果用戶把瀏覽器的隱私級(jí)別調(diào)到最高,這時(shí)瀏覽器是不會(huì)接受Cookie穴翩、這樣導(dǎo)致永遠(yuǎn)在服務(wù)器端都拿不到的JSESSIONID信息犬第。這樣就導(dǎo)致服務(wù)器端的Session使用不了。
Java針對(duì)Cookie禁用芒帕,給出了解決方案歉嗓,依然可以保證JSESSIONID的傳輸。
Java中給出了再所有的路徑的后面拼接JSESSIONID信息副签。
使用response對(duì)象中的方法完成:
需求3:瀏覽器禁用cookie遥椿,當(dāng)前servlet的session中設(shè)置ip,超鏈接跳轉(zhuǎn)另一個(gè)servlet時(shí)可以獲取ip地址淆储。
1在Session1Servlet中冠场,使用response.encodeURL(url)對(duì)超鏈接路徑拼接 session的唯一標(biāo)識(shí)
2使用瀏覽器訪問
在response對(duì)象中的提供的encodeURL方法它只能對(duì)頁(yè)面上的超鏈接或者是form表單中的action中的路徑進(jìn)行重寫(拼接JSESSIONID)。
如果我們使用的重定向技術(shù)本砰,這時(shí)必須使用下面方法完成:
1在Session1Servlet的基礎(chǔ)上增加如下代碼:
其實(shí)就是在路徑后面拼接了Session的唯一標(biāo)識(shí) JSESSIONID碴裙。
3.5.Session的生命周期(面試)
Session對(duì)象的創(chuàng)建時(shí)間:
當(dāng)前服務(wù)器啟動(dòng)之后,用戶第一次訪問某個(gè)Servlet程序的時(shí)候点额,在這個(gè)Servlet中調(diào)用getSession()方法或者調(diào)用的getSession(true),這時(shí)服務(wù)器內(nèi)部才會(huì)針對(duì)當(dāng)前這個(gè)用戶的瀏覽器創(chuàng)建一個(gè)Session容器對(duì)象舔株。
Session的銷毀時(shí)間:
1、不正常關(guān)閉服務(wù)器还棱。如果是正常關(guān)閉服務(wù)器载慈,這時(shí)服務(wù)器內(nèi)部會(huì)使用IO流中的序列化技術(shù)把這個(gè)Session對(duì)象保存在tomcat/work目錄下面。
2珍手、Session在服務(wù)器的存活時(shí)間办铡。Session對(duì)象在服務(wù)器內(nèi)部有默認(rèn)的存活的時(shí)間。一般默認(rèn)是30分鐘琳要。如果在30分鐘內(nèi)寡具,用戶沒有再對(duì)當(dāng)前這個(gè)服務(wù)器中的資源進(jìn)行任何的訪問操作,這時(shí)只要時(shí)間到達(dá)30分鐘稚补,服務(wù)器會(huì)自動(dòng)的銷毀這個(gè)session童叠。
Session的存活時(shí)間我們可以在當(dāng)前這個(gè)項(xiàng)目的web.xml中配置:
3、調(diào)用HttpSession中的銷毀Session的方法:
3.1.Session案例一次性驗(yàn)證碼登錄
驗(yàn)證碼的實(shí)現(xiàn)原理:
在一個(gè)Servlet中生成驗(yàn)證课幕,并把驗(yàn)證碼上的數(shù)據(jù)保存在Session厦坛,用戶提交驗(yàn)證碼之后,會(huì)提交給另外一個(gè)Servlet程序撰豺。在獲取用戶提交數(shù)據(jù)的Servlet中的從Session中把驗(yàn)證碼取出粪般,在取出的同時(shí)從Session中把驗(yàn)證碼刪除。
注冊(cè)頁(yè)面:register.jsp
生成驗(yàn)證碼參考:cn.itcast.session.CheckImgServlet
publicclassCheckImgServletextendsHttpServlet {
publicvoiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {
intwidth = 120;
intheight = 40;
// 先生成一張紙
BufferedImage bufi =newBufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 畫筆
Graphics g = bufi.getGraphics();
// 設(shè)置背景顏色
// 修改畫筆顏色
g.setColor(Color.white);
// 填充
g.fillRect(0, 0, width, height);
// 繪制邊框
// 設(shè)置邊框顏色
g.setColor(Color.red);
// 畫邊框
g.drawRect(0, 0, width - 1, height - 1);
// 準(zhǔn)備一些數(shù)據(jù)
String data ="ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz";
// 生成隨機(jī)對(duì)象
Random r =newRandom();
String checkcode ="";
// 生成4個(gè)隨機(jī)的數(shù)字
for(inti = 0; i < 4; i++) {
// 生成隨機(jī)顏色
g.setColor(newColor(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
// 設(shè)置字體
g.setFont(newFont("宋體", Font.ITALIC, 25));
String c = data.charAt(r.nextInt(data.length())) +"";
g.drawString(c, 10 + (20 * i), 30);
checkcode += c;
}
// 將生成的驗(yàn)證碼放到 session中
request.getSession().setAttribute("session_checkcode", checkcode);
// 畫干擾線
for(inti = 0; i < 8; i++) {
// 設(shè)置隨機(jī)顏色
g.setColor(newColor(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
// 畫線 兩點(diǎn)確定一線
g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
}
// 將圖片輸出到瀏覽器
ImageIO.write(bufi,"jpg", response.getOutputStream());
}
publicvoiddoPost(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {
}
}
注冊(cè)servlet:
3.1.Servlet三種數(shù)據(jù)范圍
下面的三個(gè)對(duì)象污桦,可以當(dāng)做容器來(lái)使用亩歹,可以保存數(shù)據(jù),因此他們也被稱為域?qū)ο蟆?/p>
ServletContext:它保存的數(shù)據(jù)所有的Servlet共享凡橱。它的范圍最大小作。開發(fā)幾乎不用。除非需要保存整個(gè)項(xiàng)目中共享的信息才會(huì)使用稼钩。
HttpSession:它是針對(duì)當(dāng)前某個(gè)用戶(瀏覽器)的一系列操作顾稀,然后在服務(wù)器端創(chuàng)建的一個(gè)容器,整個(gè)容器僅僅只能是當(dāng)前這個(gè)客戶端(瀏覽器)使用坝撑。多個(gè)客戶端(瀏覽器)静秆,它們會(huì)有不同的Session容器對(duì)象
HttpServletRequest:它的針對(duì)用戶的這次請(qǐng)求粮揉,只要請(qǐng)求和響應(yīng)結(jié)束,這個(gè)容器就消失了抚笔。一般開發(fā)中這個(gè)容器是最常用扶认。只要給request中保存了數(shù)據(jù)之后,那么就會(huì)使用轉(zhuǎn)發(fā)技術(shù)殊橙,轉(zhuǎn)發(fā)到JSP頁(yè)面上辐宾,在頁(yè)面上使用EL表達(dá)式把request中的數(shù)據(jù)取出,并顯示膨蛮。