Javaweb動態(tài)開發(fā)最重要的Servlet詳解
一.導(dǎo)入方式
由于jdk中沒有servlet對應(yīng)的jar包,所以需要咱們手動引入,有兩種方式:
1.可以采取向lib目錄導(dǎo)入servlet-api的jar包的方式
2.在maven項目中設(shè)置如下坐標(biāo),并添加相關(guān)依賴到依賴庫中即可(推薦使用這種,在maven里選擇webapp的骨架建立項目會自動給你配置好web.xml文件)
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency>
版本號可以自己定,依賴范圍要配置成provided,否則會和其他jar包沖突
二.Servlet生命周期
原生的Servlet項目都是實現(xiàn)Servlet接口,功能都是通過實現(xiàn)這個接口或者繼承HttpServlet來完成的,其實在IDEA里重寫方法的過程中所對應(yīng)的順序就是他的生命周期,以下面為例:
按照每一個方法翻譯而來的字面意思,流程是:
初始化——得到服務(wù)配置——服務(wù)——獲取服務(wù)信息——銷毀,簡言之,就是一個從初始化到服務(wù)再到消亡的過程。
初始化階段:
public void init(ServletConfig servletConfig)
當(dāng)服務(wù)器啟動,讀取web.xml文件的過程中,Tomcat加載 Servlet,加載完成后,Servlet 容器會創(chuàng)建一個 Servlet 實例 并調(diào)用 init()方法,init()方法只會調(diào)用一次,這個沒什么好解析的,就是面向?qū)ο笾蓄愄匦缘捏w現(xiàn)
服務(wù)階段:
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
這個方法的形參里有兩個ServletRequest和ServletResponse類型的接口,翻譯過來就是服務(wù)請求、服務(wù)響應(yīng),Tomcat啟動時自動裝載某些 servlet,并在 Servlet 容器啟動后,瀏覽器首次向 Servlet 發(fā)送請求,發(fā)送的請求和響應(yīng)作為參數(shù)就傳到了service方法對應(yīng)的形參里進(jìn)行處理??戳艘幌耲dk的源碼,發(fā)現(xiàn)兩個接口下面都有很多的抽象方法,至于請求和響應(yīng)在底層是怎樣執(zhí)行的源碼里啥都沒寫,目前還不知道(推測是個底層驅(qū)動)
消亡階段:
public void destroy()
從圖中規(guī)定的順序不難看出,執(zhí)行到最后的方法也就預(yù)示著Servlet的生命即將結(jié)束
在JDK的源碼中,Servlet接口下的destory()沒有方法體,應(yīng)該也是和啟動線程的start0()方法類似被開發(fā)者封裝簡化了
完整流程演示:
@WebServlet("/demo1") public class SevDemo1 implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException {System.out.println("我在初始化~~~");} @Override public ServletConfig getServletConfig() {return null;} @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("hello world!!!!");} @Override public String getServletInfo() {return null;} @Override public void destroy() {System.out.println("我走了,拜拜~~~");} }
控制臺打印的信息很好地反映了執(zhí)行情況:
至于public ServletConfig getServletConfig()
和public String getServletInfo()
在實現(xiàn)接口后重寫的方法中默認(rèn)返回的是null,應(yīng)該是兩個起補(bǔ)充作用的方法
三.繼承HttpServlet
在實際開發(fā)中采用繼承HttpServlet類的方式開發(fā)Servlet程序更加方便,因為實現(xiàn)接口重寫那麼多方法是真的麻煩,而通過繼承的方式就可以根據(jù)需要選擇性的重寫doGe()或doPost()方法就簡單很多,比如
public class HttpDemo extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("執(zhí)行 doGet()..."); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("執(zhí)行 doPost()..."); } }
至于方法體里寫什么內(nèi)容就要看對應(yīng)的業(yè)務(wù)場景了
氣氛烘托到這里了就不得不說一下GET和POST的區(qū)別了
GET&POST
以前老師是教我這樣理解的——我把一封信放在信封里郵寄出去,我可以選擇密封或者不密封,而這就會導(dǎo)致信的內(nèi)容會不會被別人看到,若是前者則對應(yīng)POST,后者就對應(yīng)GET
當(dāng)然,這只是抽象層面,而從具體方面來看:
1.從功能上來講,get是從服務(wù)器上獲取數(shù)據(jù),post是向服務(wù)器傳送數(shù)據(jù)
2.從報文上來講,在不帶參數(shù)時區(qū)別就單純是第一行方法名不同,而在帶參數(shù)時GET方法的參數(shù)放在請求頭URL中,POST方法的參數(shù)放在請求體BODY中 注:GET方法的參數(shù)寫在?后,用&分割
3.從安全性來講,其實他們都不安全,因為http是明文傳輸(在網(wǎng)頁按F12進(jìn)入開發(fā)者模式發(fā)現(xiàn)兩種方式都能看到數(shù)據(jù)信息)。但是這張圖應(yīng)該很生動形象也能反映一些問題,相比較之下POST還是比GET安全,因為數(shù)據(jù)在地址欄不可見,哈哈哈
四.Servlet相關(guān)性質(zhì)(八股文)
1.Servlet 是一個供其他 Java 程序(Servlet 引擎)調(diào)用的 Java 類,不能獨立運(yùn)行
2.對于每次訪問請求,Servlet 引擎都會創(chuàng)建一個新的 HttpServletRequest 請求對象和一個 新的 HttpServletResponse 響應(yīng)對象,然后將這兩個對象作為參數(shù)傳遞給它調(diào)用的 Servlet 的 service()方法,service 方法再根據(jù)請求方式分別調(diào)用 doXXX 方法
3.針對瀏覽器的多次 Servlet 請求,通常情況下,服務(wù)器只會創(chuàng)建一個 Servlet 實例對象, 也就是說 Servlet 實例對象一旦創(chuàng)建,它就會駐留在內(nèi)存中,為后續(xù)的其它請求服務(wù),直至 web 容器退出/或者 redeploy 該 web 應(yīng)用,servlet 實例對象才會銷毀
4.如果在<servlet>元素中配置了一個<load-on-startup>元素,那么 WEB 應(yīng)用程序在啟動時, 就會裝載并創(chuàng)建 Servlet 的實例對象、以及調(diào)用 Servlet 實例對象的 init()方法
5.在 Servlet 的整個生命周期內(nèi),init 方法只被調(diào)用一次。而對每次請求都導(dǎo)致 Servlet 引 擎調(diào)用一次 servlet 的 service 方法
——ps:刷dy整理出來的
五.Request&Response
對于這些內(nèi)部方法來說我覺得會用API就行
1.HttpServletRequest
HttpServletRequest 表示請求過來的信息:
公共接口類HttpServletRequest繼承自ServletRequest??蛻舳藶g覽器發(fā)出的請求被封裝成為一個HttpServletRequest對象。對象包含了客戶端請求信息包括請求的地址,請求的參數(shù),提交的數(shù)據(jù),上傳的文件客戶端的ip甚至客戶端操作系統(tǒng)都包含在其內(nèi)。
還是面向?qū)ο竽且惶?,封裝成類后調(diào)用里面的方法,部分常用方法如下:
public String getAuthType() | 返回這個請求的身份驗證模式 |
---|---|
public Cookie[ ] getCookies() | 返回一個數(shù)組,該數(shù)組包含這個請求中當(dāng)前的所有cookie |
public long getDateHeader(String name) | 返回指定的請求頭域的值,這個值被轉(zhuǎn)換成一個精確到毫秒的長整數(shù) |
public String getHeader(String name) | 返回一個請求頭域的值。(譯者注:與上一個方法不同的是,該方法返回一個字符串) |
2.HttpServletResponse
HttpServletResponse 表示所有響應(yīng)的信息,需要設(shè)置返回給客戶端的信息,通過 HttpServletResponse 對象來進(jìn)行設(shè)置即可,會用幾個核心API就夠了
addHeader(String name,String value) | 將指定的名字和值加入到響應(yīng)的頭信息中 |
---|---|
encodeURL(String url) | 編碼指定的URL |
setStatus(int sc) | 給當(dāng)前響應(yīng)設(shè)置狀態(tài)碼 |
setHeader(String name,String value) | 將給出的名字和值設(shè)置響應(yīng)的頭部 |
六.請求轉(zhuǎn)發(fā)模型
先前在網(wǎng)頁中輸出hello java!只是一次請求對應(yīng)一個Servlet,瀏覽器——Tomcat——Servlet沒有實現(xiàn)請求的轉(zhuǎn)發(fā),而在真實環(huán)境中網(wǎng)站不可能只進(jìn)行一次交互,往往需要在一次請求中使用到多個servlet完成
1.一個 web 資源收到客戶端請求后,通知服務(wù)器去調(diào)用另外 一個 web 資源進(jìn)行處理
2. HttpServletRequest 對象(也叫 Request 對象)提供了一個 getRequestDispatcher 方法,該 方法返回一個 RequestDispatcher 對象,調(diào)用這個對象的 forward 方法可以實現(xiàn)請求轉(zhuǎn)發(fā)
3. request 對象同時也是一個域?qū)ο?,開發(fā)人員通過 request 對象在實現(xiàn)轉(zhuǎn)發(fā)時,把數(shù)據(jù) 通過 request 對象帶給其它 web 資源處理
在實際場景中,用戶輸入信息提交后得到反饋這一過程就是典型的請求轉(zhuǎn)發(fā),就像這樣:
第一個Servlet里的情況
@WebServlet("/demo2") public class Sevdemo2 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("這里是demo2~~"); //存儲數(shù)據(jù) req.setAttribute("懶羊羊","你好!"); //請求轉(zhuǎn)發(fā) req.getRequestDispatcher("/demo3").forward(req,resp); } }
第二個Servlet里的情況
@WebServlet("/demo3") public class Sevdemo3 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("這里是demo3~~"); Object msg= req.getAttribute("懶羊羊"); System.out.println(msg); } }
當(dāng)我啟動Tomcat來訪問demo2時:
實現(xiàn)了請求的轉(zhuǎn)發(fā)!
既然是一個Servlet轉(zhuǎn)發(fā)給另一個Servlet,且是部署在同一個Tomcat中,那就說明不能訪問當(dāng)前web工程外的資源、同一次 HTTP 請求中,進(jìn)行多次轉(zhuǎn)發(fā),仍然是一次 HTTP 請求
七.請求重定向
和請求轉(zhuǎn)發(fā)比較類似,請求重定向指:一個 web 資源收到客戶端請求后,通知客戶端去訪問另外一個 web 資源,這稱之為請求重定向,還是通過API調(diào)方法來實現(xiàn),基本流程如下:
首先通過setStatus()設(shè)置響應(yīng)狀態(tài)碼,然后setHeader(“location”,“http://www.taobao.com”)設(shè)置新地址
就實現(xiàn)了請求重定向
@WebServlet("/demo2") public class Sevdemo2 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("這里是demo2~~"); //設(shè)置響應(yīng)狀態(tài)碼 resp.setStatus(302); //設(shè)置新地址 resp.setHeader("location","http://www.taobao.com") } }
還有第二種方法,其實和這也大同小異
到這里動態(tài)web的核心Servlet就介紹完了
內(nèi)容以及配圖都是作者原創(chuàng),若是覺得不錯的話可以三連一下,懶羊羊蟹蟹你~
到此這篇關(guān)于Javaweb動態(tài)開發(fā)最重要的Servlet詳解的文章就介紹到這了,更多相關(guān)Javaweb Servlet內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解析ConcurrentHashMap: put方法源碼分析
ConcurrentHashMap是由Segment數(shù)組結(jié)構(gòu)和HashEntry數(shù)組結(jié)構(gòu)組成。Segment的結(jié)構(gòu)和HashMap類似,是一種數(shù)組和鏈表結(jié)構(gòu),今天給大家普及java面試常見問題---ConcurrentHashMap知識,一起看看吧2021-06-06詳解eclipse創(chuàng)建maven項目實現(xiàn)動態(tài)web工程完整示例
這篇文章主要介紹了詳解eclipse創(chuàng)建maven項目實現(xiàn)動態(tài)web工程完整示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-12-12Java數(shù)據(jù)結(jié)構(gòu)及算法實例:快速計算二進(jìn)制數(shù)中1的個數(shù)(Fast Bit Counting)
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)及算法實例:快速計算二進(jìn)制數(shù)中1的個數(shù)(Fast Bit Counting),本文直接給出實現(xiàn)代碼,代碼中包含詳細(xì)注釋,需要的朋友可以參考下2015-06-06