一.Servlet細(xì)節(jié)
1.Servlet細(xì)節(jié)
1):一個(gè)Servlet向外暴露多個(gè)資源名稱(一般來(lái)說(shuō),一個(gè)Servlet使用一個(gè)資源名稱即可).
方式1:同一個(gè)<servlet>元素,提供多個(gè)<servlet-mapping>元素.
方式2:在<servlet-mapping>元素中提供多個(gè)<url-pattern>元素.
2):Servlet的資源名稱使用通配符表示(:表示N個(gè)任意字符).
- 方式1:/:任意的資源名稱都可以訪問(wèn)該Servlet.
推論:/system/:訪問(wèn)的資源名稱必須以/system/打頭才可以訪問(wèn)(在簡(jiǎn)單權(quán)限控制的時(shí)候使用). - 方式2:*.拓展名: 比如: *.do:凡是以.do結(jié)尾的資源名稱都可以訪問(wèn)當(dāng)前的Servlet.
3):自定義的Servlet在編寫(xiě)<servlet-name>元素的時(shí)候,文本內(nèi)容不能叫做:default.
原因是:在Tomcat根/conf/web.xml文件,有一個(gè)DefaultServlet的<servlet-name>就叫做:default.
如果我們也起名叫做:default,將會(huì)覆蓋DefaultServlet的配置.
DefaultServlet的作用是:在于訪問(wèn)靜態(tài)的資源(html/圖片/css/js等).
4):默認(rèn)情況下,Servlet的創(chuàng)建時(shí)機(jī),在第一次訪問(wèn)Servlet的時(shí)候,創(chuàng)建Servlet對(duì)象并調(diào)用init方法做初始化操作:
如果我們的某一個(gè)Servlet是用來(lái)做初始化操作的(比較耗時(shí)),那么也將會(huì)在第一次請(qǐng)求的時(shí)候才會(huì)執(zhí)行,第一用戶耗時(shí)比較長(zhǎng).
解決方案:在系統(tǒng)(Tomcat)啟動(dòng)的時(shí)候,就對(duì)初始化Servlet做創(chuàng)建以及初始化操作,啟動(dòng)耗時(shí)延遲.
在<servlet>元素中配置: <load-on-startup>數(shù)字</load-on-startup>.數(shù)字越小越優(yōu)先加載.
2.Servlet3.0新特性-注解配置
1.說(shuō)明
從JavaEE6(Tomcat7,Servelt3.0)開(kāi)始,可以使用(WebServlet)注解來(lái)取代傳統(tǒng)的XML配置.
所以我們說(shuō),從Tomcat7開(kāi)始,web.xml文件不再是必須的,但是我們一般都保留該文件.
注意:web.xml文件中的:metadata-complete="true",表示是否忽略掃描Servlet上的注解標(biāo)簽.
metadata-complete="true" :要忽略掃描注解.
metadata-complete="false":不忽略,要掃描注解.(不寫(xiě)該屬性,缺省就是false.)
2.Servlet的注解使用方式
使用WebServlet的注意:
1): metadata-complete="false"或者刪除該屬性:
2): @WebServlet("/資源名"),資源名稱必須使用/打頭.
3.注解和XML的使用對(duì)比
4.如何選擇使用
開(kāi)發(fā)中到底使用XML配置還是注解配置:
-
XML配置:
- 優(yōu)點(diǎn):直觀,清晰,可以統(tǒng)一配置,維護(hù)性較高.
- 缺點(diǎn):繁瑣,如果配置信息比較多,配置文件會(huì)臃腫.
-
注解配置:
- 優(yōu)點(diǎn):簡(jiǎn)單,高效.
- 缺點(diǎn):配置不夠清晰,不能統(tǒng)一管理,硬編碼又再次回到了Java代碼中.
在開(kāi)發(fā)中因情況而定.
一般說(shuō)來(lái),我們使用XML做統(tǒng)一通用的配置,個(gè)別的配置可以使用注解來(lái)完成.
3.安全問(wèn)題
多線程并發(fā)訪問(wèn)同一個(gè)資源,會(huì)造成線程不安全問(wèn)題.
Servlet是單例的,Servlet中的成員變量name,也就只有一個(gè)空間,后來(lái)的數(shù)據(jù)會(huì)覆蓋name空間的之前的數(shù)據(jù),
解決方案:
- 方式1:讓Servlet實(shí)現(xiàn)SingleThreadModel(過(guò)時(shí)).只允許一個(gè)線程訪問(wèn)當(dāng)前Servlet,但是效率很低.
- 方式2:在Servlet中不要使用成員變量,使用局部變量.
在service方法中定義的局部變量,每一個(gè)線程發(fā)出請(qǐng)求的時(shí)候,都會(huì)重新調(diào)用service方法.
4.Servlet總結(jié)
Servlet:其實(shí)就是一個(gè)特殊的類,繼承于HttpServlet.
作用:
- 1):輸出一個(gè)動(dòng)態(tài)網(wǎng)頁(yè).
- 2):處理用戶的請(qǐng)求.
Servlet的優(yōu)缺點(diǎn):
- 優(yōu)點(diǎn): 是動(dòng)態(tài)網(wǎng)頁(yè),跨平臺(tái), Servlet是單實(shí)例的,在Tomcat中一個(gè)Servlet就只有一個(gè)對(duì)象-->效率比較高.
- 缺點(diǎn): 輸出動(dòng)態(tài)網(wǎng)頁(yè)太惡心(JSP). Servlet的單實(shí)例提高了效率,但是卻帶來(lái)了安全性問(wèn)題.
二.Http協(xié)議無(wú)狀態(tài)帶來(lái)的問(wèn)題
1.HTTP協(xié)議:
規(guī)范了瀏覽器和服務(wù)器之間傳輸數(shù)據(jù)的格式.
Http協(xié)議是無(wú)狀態(tài)的:(健忘的人).服務(wù)器不知道上一次請(qǐng)求是哪一個(gè)客戶端發(fā)出的.
HTTP是無(wú)狀態(tài)協(xié)議宴猾,也就是沒(méi)有記憶力,每個(gè)請(qǐng)求之間無(wú)法共享數(shù)據(jù)乓搬。這就無(wú)法知道會(huì)話什么時(shí)候開(kāi)始斋配,什么時(shí)候結(jié)束珠增,也無(wú)法確定發(fā)出請(qǐng)求的用戶身份。
2.會(huì)話:
百度百科的解釋:簡(jiǎn)單為,打開(kāi)瀏覽器,訪問(wèn)一個(gè)站點(diǎn),在這一個(gè)網(wǎng)站中和服務(wù)端有多次交互,最后關(guān)閉瀏覽器,整個(gè)過(guò)程就稱之為一次會(huì)話.
在這一次會(huì)話中,用戶需要和服務(wù)端做多次交互,每一次交互都是一個(gè)(請(qǐng)求-響應(yīng)),HTTP協(xié)議是無(wú)狀態(tài)的,服務(wù)端怎么怎么你的這一次請(qǐng)求和上一次請(qǐng)求是同一個(gè)用戶發(fā)出的.
在一個(gè)會(huì)話中共享多次請(qǐng)求的數(shù)據(jù)即會(huì)話跟蹤技術(shù).
登錄郵件系統(tǒng):收郵件:
郵件系統(tǒng)流程分析:
3.解決的問(wèn)題:如何跟蹤用戶的會(huì)話信息(處理多個(gè)請(qǐng)求之間共享數(shù)據(jù)).**
方式1:在資源后面使用傳遞參數(shù)的機(jī)制.
比如: /param/list?username=iwiller .
那么在ListServlet就可以通過(guò)request.getParameter獲取參數(shù).
該方式很不安全,因?yàn)槌溄拥恼?qǐng)求參數(shù)會(huì)全部暴露在瀏覽器的地址欄.http://localhost/param/get?username=will
解決方案:
傳遞參數(shù)的時(shí)候,不要把參數(shù)存放在請(qǐng)求的行里面(瀏覽器地址欄),
最好把請(qǐng)求參數(shù),存放于請(qǐng)求頭中,如此一來(lái)瀏覽器中看不到,比較安全.--->Cookie.
方式2:Cookie.
方式3:Session.
三.Cookie
1.什么是Cookie:
解決用戶的會(huì)話跟蹤.
Cookie是客戶端技術(shù),程序把每個(gè)用戶的數(shù)據(jù)以cookie的形式寫(xiě)給用戶各自的瀏覽器何鸡。當(dāng)用戶使用瀏覽器再去訪問(wèn)服務(wù)器中的web資源時(shí)肆良,就會(huì)帶著各自的數(shù)據(jù)去筛璧。這樣,web資源處理的就是用戶各自的數(shù)據(jù)了惹恃。
客戶端技術(shù):多個(gè)請(qǐng)求時(shí)需要共享數(shù)據(jù),我們把共享數(shù)據(jù)存放于客戶端(瀏覽器)中.
原理(辦會(huì)員卡的例子):
使用Cookie和不使用Cookie的區(qū)別(請(qǐng)求/響應(yīng)中)
2.Cookie的操作:
1:創(chuàng)建Cookie對(duì)象并設(shè)置共享數(shù)據(jù)[辦一張會(huì)員卡,并填寫(xiě)卡上的信息].
Cookie c = new Cookie(String name,String value);
Cookie c = new Cookie("currentName","Will");
參數(shù):
name: 給共享數(shù)據(jù)起個(gè)名字
value: 多個(gè)請(qǐng)求之前需要共享的數(shù)據(jù)
2.把Cookie放入響應(yīng)中,響應(yīng)給瀏覽器(把會(huì)員卡交給客戶).
response對(duì)象.addCookie(c);
3.從請(qǐng)求中獲取Cookie對(duì)象,再?gòu)腃ookie中獲取共享的數(shù)據(jù)(客戶帶卡去健身房).
Cookie[] cs = req.getCookies();
4.:Cookie的屬性名和屬性值都不支持中文.
解決方案:URLEncoder對(duì)中文做編碼操作.
- 編碼(放進(jìn)Cookie之前):
Cookie cookie = new Cookie("currentName",URLEncoder.encode(username, "UTF-8"));
- 解碼(從Cookie中獲取出來(lái)):
username = URLDecoder.decode(c.getValue(), "UTF-8");
5.修改Cookie(修改Cookie中存放的共享數(shù)據(jù)).
- 方式1:獲取被修改的Cookie對(duì)象,cookie對(duì)象.setValue(新的數(shù)據(jù))(不推薦);
- 方式2:創(chuàng)建一個(gè)和被修改Cookie同名的Cookie對(duì)象,只改變value值即可.
Cookie xxx = new Cookie("currentName","lucy");
注意:此時(shí)修改重新把修改之后的Cookie響應(yīng)給瀏覽器.
6.Cookie的分類(根據(jù)Cookie存活的時(shí)間,分成兩大類).
名稱 | 解釋 |
---|---|
會(huì) 話Cookie: | 在當(dāng)前會(huì)話中有效,瀏覽器關(guān)閉就銷毀了.此時(shí)該Cookie存放在瀏覽器進(jìn)程中(缺省). |
持久化Cookie: | 可以存活指定的時(shí)間(我們需要來(lái)設(shè)置Cookie的存活時(shí)間). |
Cookie對(duì)象.setMaxAge(int seconds);設(shè)置Cookie對(duì)象存儲(chǔ)的最大時(shí)間.
7.刪除Cookie.
Cookie對(duì)象.setMaxAge(0):表示立刻刪除該Cookie對(duì)象.
8.設(shè)置訪問(wèn)路徑和域.
Cookie的path是在同一主機(jī)中指定共享Cookie夭谤,如果主機(jī)不同那么就一定不能共享Cookie,無(wú)論path是什么座舍。
需求:AServlet和BServlet共享Cookie:
- 如果:AServlet的資源路徑是/cookie/a,BServlet的資源路徑是:/cookie/b. 此時(shí)共享成功.
- 如果:AServlet的資源路徑是/cookie/a,BServlet的資源路徑是:/ooxx/b. 此時(shí)不能共享.
(1)默認(rèn)情況下會(huì)根據(jù)Servlet的相對(duì)路徑來(lái)做判斷.
若需要讓整個(gè)應(yīng)用中所有的Servlet都可以獲取該Cookie,則設(shè)置為:Cookie對(duì)象.setPath("/");
(2)如果希望不同的二級(jí)域名中可以共享Cookie沮翔,那么就要設(shè)置Cookie的domain了。
例如:music.baidu.com曲秉、map.baidu.com采蚀、tieba.baidu.com,它們的域名不同承二,但百度希望它們之間可以共享Cookie榆鼠,那么就要設(shè)置domain了。
1). 設(shè)置Cookie的path為“/”亥鸠,例如:cookie.setPath("/");
2). 設(shè)置Cookie的domain妆够,例如:cookie.setDomain(".baidu.com")识啦,其中domain中沒(méi)有指定域名前綴!
在music.baidu.com主機(jī)中的某個(gè)項(xiàng)目中保存了Cookie
在map.baidu.com主機(jī)中某個(gè)項(xiàng)目中獲取Cookie
當(dāng)然這需要配置兩個(gè)虛擬主機(jī)才行神妹。
3.Cookie的缺陷:
1):Cookie存儲(chǔ)中文的時(shí)候,操作麻煩(手動(dòng)的編碼/解碼操作);
2):Cookie存儲(chǔ)在瀏覽器中,多個(gè)人使用共同的一臺(tái)的電腦的時(shí)候,不安全.
3):Cookie的文件大小和數(shù)量是有限制的.
- Cookie大小限制在4KB之內(nèi)颓哮;
- 一臺(tái)服務(wù)器在一個(gè)客戶端最多保存20個(gè)Cookie;
- 一個(gè)瀏覽器最多可以保存300個(gè)Cookie鸵荠;
4):Cookie的value只能存儲(chǔ)String類型的數(shù)據(jù),一個(gè)Cookie只能存儲(chǔ)一個(gè)共享數(shù)據(jù).
若需要共享多個(gè)數(shù)據(jù),就得創(chuàng)建多個(gè)Cookie對(duì)象.--->操作麻煩
如果Cookie的Value可以存儲(chǔ)Object類型,我們就可以把多個(gè)數(shù)據(jù)封裝成對(duì)象,再做存儲(chǔ).
5):Cookie在設(shè)計(jì)上的問(wèn)題.
Cookie的設(shè)計(jì):把客戶端和服務(wù)端的識(shí)別數(shù)據(jù)存放于客戶端中,這個(gè)在設(shè)計(jì)上有點(diǎn)不合理.
最好的設(shè)計(jì)方式:把識(shí)別數(shù)據(jù)存放于服務(wù)端,客戶端只需要存儲(chǔ)一個(gè)標(biāo)志即可.
新會(huì)員過(guò)來(lái), 把新會(huì)員的數(shù)據(jù)錄入到系統(tǒng)中(健身房這里/服務(wù)端).
下一次,會(huì)員來(lái)健身,只要報(bào)手機(jī)號(hào)碼,就可以從系統(tǒng)中找到該用戶的識(shí)別數(shù)據(jù).---->Session.
四.Session
1.什么是session
Session其實(shí)就是一個(gè)特殊的會(huì)話Cookie,瀏覽器關(guān)閉Session就銷毀了.
Session是服務(wù)器端技術(shù)(把識(shí)別數(shù)據(jù)/共享數(shù)據(jù)存放于服務(wù)端)冕茅,利用這個(gè)技術(shù),服務(wù)器在運(yùn)行時(shí)可以為每一個(gè)用戶的瀏覽器創(chuàng)建一個(gè)其獨(dú)享的session對(duì)象蛹找,由于session為用戶瀏覽器獨(dú)享姨伤,所以用戶在訪問(wèn)服務(wù)器的web資源時(shí),可以把各自的數(shù)據(jù)放在各自的session中庸疾,當(dāng)用戶再去訪問(wèn)服務(wù)器中的其它web資源時(shí)乍楚,其它web資源再?gòu)挠脩舾髯缘膕ession中取出數(shù)據(jù)為用戶服務(wù)。
cookie的方式
session的方式
session對(duì)象
session和cookie的區(qū)別
2.操作Session:
1.創(chuàng)建和獲取Session對(duì)象.
// 如果當(dāng)前存在Session對(duì)象,則直接返回,如果當(dāng)前沒(méi)有Session對(duì)象,先創(chuàng)建一個(gè)Session對(duì)象,再返回.
HttpSession session = request對(duì)象.getSession(true);
// 如果當(dāng)前存在Session對(duì)象,則直接返回,如果沒(méi)有,在則返回null.
HttpSession session = request對(duì)象.getSession(false);
//等價(jià)于 request對(duì)象.getSession(true).
HttpSession session = request對(duì)象.getSession();
2.往Session中存儲(chǔ)共享數(shù)據(jù).
session對(duì)象.setAttribute(String name,Object value);
- 0):一般的,我們把存儲(chǔ)在session中的屬性起名為:XXX_IN_SESSION.
- 1):因?yàn)镾ession的setAttribute方法支持Object類型,所以我們可以把多個(gè)共享數(shù)據(jù)封裝成對(duì)象,再存儲(chǔ)到session中.
session.setAttribute("USER_IN_SESSION",user對(duì)象); - 2):一般的,為了多態(tài)服務(wù)器之間共享session中的數(shù)據(jù),我們把session中的對(duì)象實(shí)現(xiàn)java.io.Serializable接口.
當(dāng)某一個(gè)對(duì)象只有實(shí)現(xiàn)java.io.Serializable接口之后,才可以做序列化操作.
序 列化: 把對(duì)象的數(shù)據(jù)以二進(jìn)制的形式存儲(chǔ)到文件中.------>網(wǎng)絡(luò)傳輸.
反序列化: 把二進(jìn)制形式的數(shù)據(jù)恢復(fù)成Java對(duì)象.
3.獲取Session中存儲(chǔ)的數(shù)據(jù).
Object value = session對(duì)象.getAttribute(String name);
4.刪除Session(刪除Session中存儲(chǔ)的共享數(shù)據(jù))[登錄注銷]:
- 方式1:session對(duì)象.remove(String name);從當(dāng)前session中刪除指定屬性名的屬性.
- 方式2:session.invalidate();銷毀session對(duì)象,從而session中的數(shù)據(jù)全部沒(méi)了.
5.Session的超時(shí)管理.
超時(shí)時(shí)間:用戶的兩次操作的最大間隔時(shí)間:超時(shí)時(shí)間到了,就會(huì)銷毀Session.
session對(duì)象.setMaxInactiveInterval(int seconds):
一般說(shuō)來(lái):不用設(shè)置,Tomcat中默認(rèn)為30分鐘.
6.URL重寫(xiě).
Session其實(shí)也就是一個(gè)會(huì)話Cookie(瀏覽器關(guān)閉之后,瀏覽器存儲(chǔ)的jsessionid消失了,session對(duì)象在服務(wù)端依然存在).
瀏覽器可以禁用Cookie(不接受Cookie),非常不推薦的,操作相當(dāng)麻煩.
解決方案:手動(dòng)的在每一個(gè)資源后面攜帶:;jsessionid= session的id值.
http://localhost/session/get ------>因?yàn)闉g覽器沒(méi)有存儲(chǔ)session的id值,所以找不到服務(wù)端的共享數(shù)據(jù)內(nèi)存地址.
http://localhost/session/get;jsessionid=FACF8BD9AFB39C1A85A1B1FDC1978923 .
URL重寫(xiě):
String newUrl = response對(duì)象.encodeURL(String oldUrl);
String newUrl = response對(duì)象.encodeURL("session/get");返回:/session/get;jsessionid=FACF8BD9AFB39C1A85A1B1FDC1978923
五.總結(jié)
解決用戶的會(huì)話跟蹤問(wèn)題(實(shí)現(xiàn)多個(gè)請(qǐng)求之間共享數(shù)據(jù)):
Cookie: 客戶端技術(shù):把共享數(shù)據(jù)存儲(chǔ)在瀏覽器中.
Session:服務(wù)端技術(shù):把共享數(shù)據(jù)存儲(chǔ)在服務(wù)端,只是給了客戶端一個(gè)地址(jesseionid).
電子商城的購(gòu)物車:
1):session來(lái)做:瀏覽器關(guān)閉,購(gòu)物車中的數(shù)據(jù)也就消失了.
2):如果沒(méi)有登錄: 此時(shí)把購(gòu)物車中的商品信息存儲(chǔ)到cookie中.
3):一旦登錄,先讀取該站點(diǎn)的Cookie,把商品信息持久化到數(shù)據(jù)庫(kù).
Cookie的應(yīng)用:
1):記住多久不用登錄.
2):購(gòu)物車
3):存儲(chǔ)網(wǎng)站的個(gè)人愛(ài)好設(shè)置.
4):單點(diǎn)登錄(針對(duì)多個(gè)應(yīng)用).
Session的應(yīng)用:
1):登錄信息存儲(chǔ)到session中.
2):網(wǎng)站需要統(tǒng)計(jì)在線會(huì)員人數(shù).