什么是Servlet
- sun公司制定一種擴展Web服務器功能的組件規(guī)范
擴展Web服務器功能
- web服務器只能夠處理靜態(tài)的資源請求(需要事先將HTML文件寫好),不能夠處理動態(tài)資源請求(需要計算生成HTML),所有需要擴展??梢允褂肧ervlet來擴展web服務器功能,當web服務器收到請求之后,如果需要計算,則交給Servlet來處理。
- 注:常見的文本服務器:Apache,iis,nginx等。
組件規(guī)范
- 什么是組件:符合規(guī)范,實現(xiàn)部分功能,并且部署到相應的容器里面才能運行的軟件模塊。Servlet就是一個組件,需要部署到Servlet容器里面才能運行。
- 什么是容器:符合規(guī)范,提供組件的運行環(huán)境的程序。Tomcat就是一個Servlet容器,為Servlet提供運行環(huán)境(提供網(wǎng)絡相關的服務)
如何寫Servlet
1、寫一個java類,實現(xiàn)Servlet接口或者繼承HttpServlet類(通常繼承HttpServlet)。
2、編譯。
3、打包。即創(chuàng)建一個具有如下結構的文件夾。
appname(應用名)
WEB-INF
classes(.class)
lib(.jar)
web.xml(部署描述文件)
html文件
4、部署。將第三步創(chuàng)建好的文件夾拷貝到容器響應的位置。[可以將整個文件夾使用jar先壓縮成.war為后綴的文件,然后在拷貝。]
5、啟動容器,訪問Servlet。
http://ip:port/appname/url-pattern
url-pattern在web.xml當中配置
Servlet是如何運行的
比如,在瀏覽器輸入 http://ip:port/day01/hello
1、瀏覽器依據(jù)ip和port建立連接。
2、瀏覽器將相關數(shù)據(jù)放到請求數(shù)據(jù)包中,然后發(fā)送給服務器。
3、服務器解析請求數(shù)據(jù)包,將解析到的數(shù)據(jù)添加到request對象,同時創(chuàng)建一個response對象。
4、服務器創(chuàng)建Servlet對象,然后調(diào)用該對象的service方法。
注:服務器會將request和response對象作為參數(shù)傳遞過來,開發(fā)人員只需要調(diào)用這兩個對象的方法就可以了,不用考慮網(wǎng)絡相關問題。比如,要讀取請求數(shù)據(jù)包中的數(shù)據(jù),只需要調(diào)用request對象的方法就可以了。類似的,要向瀏覽器發(fā)送處理結果,只需要調(diào)用response對象的方法就可以了。
5、服務器從response對象中獲得處理結果,然后創(chuàng)建響應數(shù)據(jù)包并發(fā)送給瀏覽器。
6、瀏覽器解析響應數(shù)據(jù)包,生成相應的頁面。
常見的問題
- 404
1、含義:服務器依據(jù)請求路徑找不到對應的資源。
2、產(chǎn)業(yè)原因:a、請求路徑寫錯。b、應用沒有部署或者部署失敗。 - 500
1、含義:系統(tǒng)出錯。
2、產(chǎn)生原因:a、沒有嚴格按照規(guī)范些代碼(包括部署描述寫錯)b、代碼不嚴謹(比如請求參數(shù)不做檢查,直接類型轉換) - 405
1、含義:找不到處理方法
2、產(chǎn)生原因:service方法沒有正確重寫
http協(xié)議
什么是http協(xié)議
是一種網(wǎng)絡應用層協(xié)議,規(guī)定了瀏覽器與web服務器之間如何通信以及相應的數(shù)據(jù)結構。
a、tcp/ip協(xié)議:屬于傳遞層和網(wǎng)絡層協(xié)議,保證數(shù)據(jù)可靠的傳遞。http協(xié)議屬于應用層協(xié)議,需要依賴tcp/ip協(xié)議來傳遞數(shù)據(jù)包。
b、瀏覽器與web服務器之間如何通信:建立連接,發(fā)送請求,發(fā)送響應,關閉連接
特點:一次請求,一次連接
這樣做的好處是服務器可以利用有限的連接做盡可能多的請求服務-
數(shù)據(jù)包的結構
1)請求數(shù)據(jù)包
a、請求行(請求方式,請求資源路徑,協(xié)議版本)b、消息頭 消息頭四一些鍵值對(使用“: ”分隔),瀏覽器與web服務器之間可以通過消息頭來傳遞一些特點的信息。比如,瀏覽器可以通過發(fā)送“user-age”消息頭,告訴瀏覽器的類型和版本。 c、實體類容 只有當請求方式有post時,實體內(nèi)容才會有數(shù)據(jù),請求方式為get時,實體內(nèi)容為空。2)響應數(shù)據(jù)包
a、狀態(tài)行(協(xié)議版本和狀態(tài)碼,狀態(tài)描述)
200 :正常
500 :系統(tǒng)出錯
404 :請求路徑出錯
b、消息頭
服務器也可以發(fā)送一些消息頭給瀏覽器,比如,可以發(fā)送“content-Type”消息頭,告訴瀏覽器,服務器返回的數(shù)據(jù)類型
c、實體內(nèi)容
程序處理結果,瀏覽器會解析出來,生成相應的頁面。 兩種請求方式
(1)get請求
a、哪些情況瀏覽器會發(fā)送get請求?
在瀏覽器地址欄直接輸入某個地址
點擊鏈接
表單默認的提交方式
b、特點
會將請求參數(shù)添加到請求資源路徑的后面,只能提交少量的數(shù)據(jù)(2k)給服務器。
會將請求參數(shù)顯示在瀏覽器地址欄,不安全
(2)post請求
a、哪些情況下,瀏覽器會發(fā)送post請求
將表單的method屬性設置為post
b、特點
會將請求參數(shù)添加到實體類容中,可以提交大量的數(shù)據(jù)給服務器
不會將請求參數(shù)顯示在瀏覽器地址欄,相對安全
(http協(xié)議并不會對數(shù)據(jù)加密,所有對于敏感數(shù)據(jù)需要進行加密)
Servlet輸出中文如何處理
- 為什么吹產(chǎn)生亂碼?
out.println()默認使用ISO-8859-1來編碼(不支持中文) - 處理response.setContentType("text/html;charset=utf-8");
如何讀取參數(shù)值
request.getParameter(String paramName)
- 如果請求參數(shù)名寫錯,獲得null
- 表單提交時,不填寫任何數(shù)據(jù),會獲得空字符串
String[] request.getParameterValues(String paramName)
- 當有多個請求參數(shù)名相同時,使用此方法
- 對于多選框和單選框,如果一個都不選,會獲得null值
表單包含有中文參數(shù),如何處理
- 為什么會有亂碼
當提交表單時,瀏覽器會按照打開該表單所在的頁面時的字符集來對中文參數(shù)進行編碼。比如使用utf-8來編碼,而服務器端默認使用ISO-8859-1來解碼。所有會產(chǎn)生亂碼 - 如何處理
-- get請求:可以修改服務器端的配置,在servers中的server.xml添加URIEncoding="utf-8"
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="utf-8" />
-- post請求:request.setCharacterEncoding(String charset);
DAO (Data Access Object )
- 什么是DAO:封裝了數(shù)據(jù)訪問邏輯的對象
- 如何寫DAO:
1、寫一個java類,用于存放從數(shù)據(jù)庫中查詢得到的數(shù)據(jù)。
2、寫DAO類,該類封裝了數(shù)據(jù)庫訪問邏輯。 - DAO的優(yōu)點:
a、方便測試:比如,如果將數(shù)據(jù)庫訪問代碼寫在Servlet里面,需要部署應用才能測試。而將數(shù)據(jù)庫訪問代碼寫在DAO類里面,可以直接測試。
b、方便分工協(xié)作
c、方便代碼的維護:比如,數(shù)據(jù)訪問邏輯發(fā)送改變,不會影響到Servlet。
重定向
- 什么是重定向:服務器通知瀏覽器向某個地址欄發(fā)送請求。
服務器通過發(fā)送302狀態(tài)碼和Location消息頭(該消息頭的值是一個地址,一般稱為重定向地址),瀏覽器收到之后,會立即向重定向地址發(fā)送請求。 - 如何重定向:response.sendRedirect(String url);
- 重定向的細節(jié):重定向之前,容器會先清空response對象上存放的所有數(shù)據(jù)。(實體內(nèi)容為空)
- 特點:
a、重定向的地址是任意的。
b、重定向之后,瀏覽器地址欄會發(fā)送變化。
jsp
- jsp是什么:jsp是sun公司制定的一種服務端的動態(tài)技術規(guī)范。
因為雖然可以使用Servlet生成動態(tài)頁面,但是過于繁瑣,不好維護,所以sun才制訂jsp規(guī)范。jsp是一個以.jsp為后綴的文件(主要內(nèi)容為HTML和少量的java代碼),容器會將jsp文件轉換為一個對應的Servlet然后執(zhí)行。
jsp本質就是一個Servlet! - jsp文件中可以添加哪些內(nèi)容
1、html(css,javascript)直接寫即可。
2、java代碼
方式一:java代碼片段
<% java代碼 %>
方式二:jsp表達式
<%= java表達式 %> - jsp是如何執(zhí)行的
1、階段1:容器先將jsp轉換成一個對應的Servlet
html(css,JavaScript)------>在service方法里面,使用out.write輸出。
<% %> ------->在service方法里面,照搬。
<%= %> ---------->在service方法里面,使用out.print輸出
2、階段2:容器調(diào)用該Servlet
需要將Servlet編譯,然后實例化,調(diào)用對應的service方法。 - 隱含對象
a、什么是隱含對象:直接可以使用的對象。
b、為什么可以直接使用隱含對象:容器在將jsp轉換成對應的Servlet時,會自動添加獲得這些對象代碼。
指令
- 什么是指令:通過指令,可以告訴容器在將jsp轉換成Servlet時做一些額外的處理。
- 語法:<%@ 指令名 屬性="值" %>
注:如果有多個屬性,使用空格隔開 - page指令
import屬性:指定要導入的包名
<%@ page import="java.util.,java.text." %>
contentType屬性:指定response.setContentType方法的屬性值
pageEncoding屬性:告訴容器,在讀取jsp文件的內(nèi)容時,使用該屬性指定的字符集編碼
轉發(fā)
- 什么是轉發(fā):一個web組件將未完成的處理,通過容器交給另外一個web組件繼續(xù)做。
注:web組件指的是servlet或者jsp。 - 如何轉發(fā):
1、綁定數(shù)據(jù)到request對象上。
request.setAttribute(String name,Object);
注:name:綁定名 obj:綁定值
String request.getAttribute(String name);
2、獲得轉發(fā)器
RequestDispatcher rd = request.getRequestDispatcher(String url);
注:url是轉發(fā)的地址,通常是一個jsp
3、轉發(fā)
rd.forward(request,response); - 轉發(fā)的特點:
1、轉發(fā)的地址是有限制的,要求時同一個web應用。
2、轉發(fā)之后,瀏覽器地址沒有改變。
轉發(fā)與重定向的區(qū)別
- 能否共享request對象
轉發(fā)可以,重定向不可以
當請求到達容器,容器會創(chuàng)建request對象和response對象,當響應發(fā)送完畢,容器會銷毀這兩個對象。也就是說,request對象和response對象的生存時間是一次請求和響應期間存在的。 - 目的地是否有限制
轉發(fā)有限制,重定向沒有。
轉發(fā)地址要求屬于同一個web應用,重定向地址是任意的。 - 瀏覽器的地址欄的地址有無變化
轉發(fā)沒有,重定向有變化。 - 一件事是否已經(jīng)做完
轉發(fā)是一件事沒有做完,讓另外一個web組件繼續(xù)做;而重定向是一件事已經(jīng)做完,再做另外一件事。
狀態(tài)管理
- 什么是狀態(tài)管理
將瀏覽器與web服務器之間多次交互當做一個整體來處理,并且將多次交互所涉及的數(shù)據(jù)(即狀態(tài))保存下來。 - 如何進行狀態(tài)管理
a、將狀態(tài)保存在瀏覽器(Cookie)
b、將狀態(tài)保存在服務端(Session)
Cookie
- 什么是Cookie
服務器臨時存放在瀏覽器端的少量數(shù)據(jù),用于跟蹤用戶的狀態(tài)。 - 工作原理
當瀏覽器訪問服務器時,服務器會將少量數(shù)據(jù)以set-cookie消息頭的方式發(fā)生給瀏覽器,瀏覽器會將這些數(shù)據(jù)臨時保存下來;當瀏覽器再次訪問服務器時,會將這些數(shù)據(jù)以cookie消息頭的方式發(fā)生給服務器。 - 添加Cookie
Cookie c = new Cookie(STring name,String value);
response.addCookie(c);
注:cookie只能存放字符串 - 讀取COokie
Cookie[] request.getCookies();
String cookie.getName();
String cookie.getValue(); - cookie的生存時間
默認情況下,瀏覽器會將cookie保存在內(nèi)存里。瀏覽器關閉,則cookie會被刪除
cookie.setMaxAge(int seconds);
注:a、單位是秒
b、當seconds>0時,瀏覽器會將cookie保存在硬盤上,當超過指定時間,cookie會被刪除。
c、當seconds<0時,瀏覽器會將cookie保存在內(nèi)存里面。
d、當seconds=0時,瀏覽器會立即刪除cookie。 - cookie編碼問題
a、什么是cookie的編碼問題:cookie只能存放合法的ASCII字符中文需要轉換成合法的ASCII字符的形式才能存放。
b、如何處理
String URLEncoding.encoding(String str,String charset);
String uRLDecoder.decode(String str,String charset);
c、建議:不管是否為中文,最好統(tǒng)一編碼處理。 - cookie的路徑問題
a、什么是cookie的路徑問題
瀏覽器訪問服務器時,會比較請求地址是否與cookie的路徑匹配,只有匹配的cookie才會被發(fā)送。
b、cookie的默認路徑
cookie的默認路徑等于添加該cookie的web組件的路徑。
c、匹配規(guī)則:請求路徑必須等于cookie的路徑或者是其子路徑,只有滿足該條件的cookie才會被發(fā)送
d、修改cookie的路徑:cookie.setPath(String path); - cookie可以被用戶進制
a、cookie可以被用戶進制
b、cookie不安全。對于敏感數(shù)據(jù),盡量避免存放在cookie里,如果一定要存放,要加密之后再存放。
c、cookie只能存放少量的數(shù)據(jù)(約4k)
d、cookie個數(shù)有限制
e、cookie只能存放字符串
session(會話)
- 什么是session:服務器端為了保存用戶狀態(tài)而創(chuàng)建的一個特殊的對象
- session工作原理:當瀏覽器訪問服務器時,服務器創(chuàng)建session對象(該對象有一個唯一的ID,以便稱為sessionId),服務器會將sessionId以cookie的方式發(fā)生給瀏覽器,當瀏覽器再次訪問服務器時,會將sessionID發(fā)生過來,服務器依據(jù)sessionID找到對應的session。
- 如何獲得session對象:
方式一:HttPSession session = request.getSession(boolean flag);
注:HttpSession是一個接口,session對象是一個符合該接口的對象。
當flag為true時,先查看請求中有無sessionId,如果沒有則創(chuàng)建一個session,有則依據(jù)該sessionId查找對應的session對象,如果找到了則返回該對象,如果找不到,則創(chuàng)建一個新的session對象。
當flag為false時,先查看請求中有沒有sessionId,如果沒有,返回null,如果有,依據(jù)sessionId查找對應的session,如果找到返回session,找不到返回null。
方式二:HttPSession session = request.getSession();
等價于request.getSession(true); - 常用方法:
setAttribute(String name,Object obj);
Object getAttribute(String name);//不存在返回null
removeAttribute(String name);
String getId(String name); - session超時
1、服務器會將空閑時間過長的session對象刪掉。(一般是30分鐘)
2、如何修改超時時間長度
方式一:修改web.xml
方式二:session.setMaxInactiveInterval(int seconds);
兩次請求之間的最大間隔 - 刪除session
session.invalidate(); - session驗證
1、在登錄成功之后綁定一些數(shù)據(jù)到session對象上
session.setAttribute("user",user);
2、當用戶訪問需要保護的資源時,進行session驗證:
Object user = session.getAttribute("user");
if(user == null){
//沒有登錄
response.sendRedirect("login.jsp");
}
Cookie和Session比較
- session相對于cookie的優(yōu)點:更安全,能存放更多的數(shù)據(jù),支持更豐富的數(shù)據(jù)類型。但是session會占用服務端的內(nèi)存空間,如果用戶量很大,就需要占用大量的內(nèi)存空間
路徑問題
指的鏈接、表單提交、重定向和轉發(fā)時,如何填寫路徑
- 相對路徑
不以"/"開頭的路徑。 - 絕對路徑
以"/"開頭的路徑。 - 如何寫絕對路徑
鏈接、表單提交、重定向從應用名開始寫,轉發(fā)從應用名之后開始寫。
注:一定不要將應用名直接寫在路徑里,使用request.getContextPath()獲得應用名
Servlet的生命周期
什么是Servlet的生命周期
Servlet容器如何創(chuàng)建Servlet對象,如何對該對象進行初始化處理、如何調(diào)用該對象的方法來處理請求、以及如何銷毀該對象的整個過程。Servlet的生命周期分為哪幾個階段
1、實例化
a、什么是實例化:容器調(diào)用Servlet的構造器,創(chuàng)建Servlet對象。
b、什么時候實例化:
情形1:容器收到請求之后
情形2:容器啟動之后,立即創(chuàng)建相應的實例(需要額外的配置)
<load-on-startup>1</load-on-startup>(值小的先創(chuàng)建)
2、初始化
a、什么是初始化
容器調(diào)用servlet對象的init方法(執(zhí)行一次)
b、GenericServlet已經(jīng)提供了init方法的實現(xiàn)
會將容器傳遞過來的ServletConfig對象保存下來,并且提供了getServletConfig來獲得該對象。
如果要實現(xiàn)自己的初始化處理邏輯,只需要override GenericServlet的init方法
c、初始化參數(shù)
配置初始化參數(shù)
讀取初始化參數(shù)
3、就緒
a、什么是就緒:容器調(diào)用Servlet的service方法來處理請求
b、HttpServlet已經(jīng)提供了service方法的實現(xiàn)
該方法會依據(jù)請求類型(get/post)調(diào)用對應的doXXX方法。
doXXX方法只拋出一個異常。
開發(fā)人員只有兩個選擇:
override doXXX方法
override service方法
4、銷毀
a、什么是銷毀:容器在刪除servlet對象之前,會調(diào)用該對象的destory方法(值執(zhí)行一次)
b、GenericServlet已經(jīng)提供了destory方法的實現(xiàn)。
該方法實際上什么都沒有做,我們可以override該方法,來實現(xiàn)自己的銷毀處理邏輯。
- 相關的接口與類
a、Servlet接口
init(ServerConfig config)
service(ServletRequest req, ServletResponse resp)
destory()
b、GenericServlet抽象類
實現(xiàn)了Servlet接口中的部分方法(init,destory)
c、HttpServlet抽象類
繼承了GenericServlet,實現(xiàn)了service方法。
過濾器
- 過濾器是什么:Servlet規(guī)范當中定義的一種特殊的組件,用來攔截Servlet容器的調(diào)用過程。
注:Servlet容器收到容器請求之后,如果有過濾器,會先調(diào)用過濾器。 - 如何寫過濾器:
1、寫一個java類實現(xiàn)Filter接口。
2、在接口方法當中,實現(xiàn)攔截處理邏輯。
3、配置過濾器(web.xml)。 - 過濾器的優(yōu)先級:當有多個過濾器攔截的要求,則容器會依據(jù)<filter-mapping>的先后順序倆執(zhí)行。
- 初始化參數(shù):
監(jiān)聽器
- 什么是監(jiān)聽器:Servlet規(guī)范當中定義的一種特殊組件,用來監(jiān)聽容器產(chǎn)生的事件并進行相關的處理。
注:容器產(chǎn)生的事件主要分為兩類,分別是
1)、生命周期相關的事件:容器創(chuàng)建或者銷毀request、session、servlet上下文產(chǎn)生的事件
2)、綁定數(shù)據(jù)相關的事件:調(diào)用了request、session、servlet上下文的setAttribute和removeAttribute方法時產(chǎn)生的事件.
Servlet上下文
- 什么是Servlet上下文:容器啟動之后,會為每一個web應用創(chuàng)建唯一的一個符合ServletContext接口要求的對象(即Servlet上下文),該對象會一直存在,除非容器關閉。
- 如何創(chuàng)建Servlet上下文:ServletConfig、FilterConfig、GenericServlet、HttPSession都提供了getServletContext方法。
- 作用:
1)綁定數(shù)據(jù)
setAttribute、getAttribute、removeAttribute
比較request、session、servlet上下文綁定數(shù)據(jù)的區(qū)別:
a、在滿足使用條件的情況下,優(yōu)先使用生命周期短的。(request<session<servlet上下文)
b、綁定到session對象的數(shù)據(jù),只有與該session對應的用戶能訪問;而綁定到servlet上下文的數(shù)據(jù),所有用戶都能共享。
使用上下文讀取全局的初始化參數(shù)
如何開發(fā)一個監(jiān)聽器
1、寫一個java類,然后實現(xiàn)相應的監(jiān)聽接口
注:要依據(jù)監(jiān)聽的事件類型,選擇實現(xiàn)相應的接口,比如,要監(jiān)聽session對象的創(chuàng)建和銷毀,實現(xiàn)HttpSessionListener接口。
2、在接口方法中,實現(xiàn)監(jiān)聽處理邏輯。
3、配置監(jiān)聽器。
容器如何處理請求資源路徑
- 容器默認訪問的是一個Servlet,所以,會查看web.xml配置,看有沒有匹配的servlet。
有三種<url-pattern>寫法:
精確配置
通配符匹配:使用""匹配零個或多個任意字符
后綴匹配:使用"."開頭,后接一個后綴 - 如果沒有查到匹配的servlet,容器會查看相應位置的文件
如何讓一個Servlet處理多種請求
1、 采用后綴匹配
2、 分析請求資源路徑,進行相應的處理
Servlet的線程安全問題
- 為什么說Servlet會有線程安全問題
a、容器對于某個Servlet,只會創(chuàng)建一個實例。
b、容器收到一個請求,就會啟動一個線程安全,由該線程來調(diào)用對應的Servlet實例的方法來處理請求。
這樣,就有可能產(chǎn)生線程安全問題,比如多個線程去修改servlet的某個屬性值。
- 如何解決:使用synchronize對有可能產(chǎn)生線程安全問題的代碼塊加鎖。
使用synchronize加鎖會影響性能。
Servlet小結
1、Servlet基礎
2、Servlet核心
3、數(shù)據(jù)庫訪問
4、過濾器與監(jiān)聽器
5、典型案例