JavaWeb—Servlet基礎(細節(jié)版,相當細節(jié))

JavaWeb—Servlet基礎(細節(jié)版,相當細節(jié))

?

什么是Servlet?

Servlet就是一個普通的類,只不過這個類能夠接受和處理請求,并且做出響應。提到Servlet就繞不開Servlet容器,那么什么又是Servlet容器呢?通俗的講就是實現Servlet標準管理輔助Servlet類工作的工具。Servlet和Servlet容器在我看來就是子彈和槍的關系,通過對標準化接口的實現互相配合,彼此依存又獨立發(fā)展。在大部分的情況下我們又稱Servlet容器為服務器,常用的有Tomcat等。

一個HTTP來了又走經歷了什么?

HTTP(超文本傳輸協議):是互聯網通信的基礎,屬于 TCP/IP 模型中的應用層協議,當瀏覽器與服務器進行互相通信時,需要先建立TCP 連接,之后服務器才會接收瀏覽器的請求信息(request),當接收到信息之后,服務器返回相應的信息(response)。最后瀏覽器接受對服務器的信息應答后,對這些數據進行解釋執(zhí)行(解析HTML文件和各種資源進行展示)。

HTTP是一個無狀態(tài)的連接協議。

所謂無狀態(tài):

根據早期的HTTP協議,每次request-reponse時,都要重新建立TCP連接。TCP連接每次都重新建立,所以服務器無法知道上次請求和本次請求是否來自于同一個客戶端。因此,HTTP通信是無狀態(tài)(stateless)的。服務器認為每次請求都是一個全新的請求,無論該請求是否來自同一地址?,F在,雖然HTTP協議允許TCP連接復用,以節(jié)省建立連接所耗費的時間,但無狀態(tài)的特性依舊被保留。

準備階段

為了迎接HTTP的到來,首先我們需要有一個Servlet類,并且告訴Servlet容器自己的存在,這兩個準備步驟就是創(chuàng)建Servlet類和寫入配置文件

正如上文所講,類和Servlet容器之間的配合是通過接口實現的,一個類只需要實現特定的接口,就可以稱為一個Servlet類,并且能夠被Servlet所接受,嗯,想來這就是接口的解耦和。

準備一個Servlet類

擁有一個Servlet類的三種方案

  1. 直接實現Servlet接口(interface)
  2. 繼承GenericServlet類(abstract)
  3. 繼承HttpServlet類(abstract)

在直接實現或者間接實現Servlet接口之后我們需要重寫其中的service方法,到此Servlet就準備好了。

寫入配置文件

配置文件是一個固定的寫法,主要就是為了告訴Servlet容器自己在哪

<servlet>
    <servlet-name>自定義Servlet的別名</servlet-name>
    <servlet-class>Servlet類的全類名</servlet-class>
</servlet>
<servlet-mapping>
    <servelt-name>自定義Servlet的別名</servelt-name>
    <url-pattern>自定義路徑</url-pattern>
</servlet-mapping>

接受請求

Servlet容器開啟服務之后就可以迎接request的到來了,當這個HTTP請求到達Servlet容器(以Tomcat為例)的時候,Tomcat看到有HTTP來,就把它帶到要去的那個地方(項目名),到了地點之后,Tomcat會拿出花名冊(web.xml)讓request挑一個(0.0)。

結果,不用挑有指定的,那就好辦了。

Tomcat在部署文件中找 servlet-mapping 中與之匹配的 url-pattern,根據這個 url-pattern 的 servlet-name 映射到真正的 servlet-class ,然后調用相應的 Servlet 類。

擴展內容:xml

xml全稱是Extensible Markup Language可擴展標記語言,看到這個難免會想起來HTML,他們有什么關系呢?為什么有了HTML語言還要xml語言呢?

認真的講他們最大的關系就是都以ml結尾了,哈哈,開個玩笑。

HTML我們是很熟悉的,在使用的時候不難發(fā)現其中的標簽都是定義好的,全世界的HTML文檔用的是同一套標記的語法。

而xml更具有個性化,其中的標簽不僅可以用別人的定義好的,也可以自己定義。書寫一個xml有兩個相關的規(guī)則,一個是標簽規(guī)則,另一個就是校檢規(guī)則,校檢規(guī)則是用來告訴程序標簽之間的規(guī)則,這個東西被稱之為文檔類型定義 Document Type Definition , 簡稱 DTD 這兩個規(guī)則都是可以自定義的(所謂擴展),所以我們在書寫不同的xml文件的時候,會發(fā)現標簽規(guī)則是不一樣的。

從這些層面上來說HTML語言也可以說是xml中的一種,HTML5就是最新的校檢規(guī)則(不知道這么理解有沒有問題???)

<!-- 我們不難發(fā)現很多xml文檔的文檔聲明中都有聲明其文檔符合的校檢規(guī)則 -->
<!-- web.xml -->
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
XML Schema是dtd的改進版
<!-- mybatis-config.xml -->
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" >

生命周期

通過以上的步驟Tomcat就找到了HTTP想要見到的那個Servlet了,但是這個類也許準備好了,也許沒有,我們假定這個request是第一次來。這時候就開始了Servlet的生命周期了。

  1. 因為是第一次請求,Tomcat會調用Servlet類的無參構造方法,創(chuàng)建這個Servlet的對象。

  2. 之后初始化,會調用init方法,這個方法會對Servlet類做一些初始化的工作,需要注意的這個方法在Servlet的一生中只會執(zhí)行這么一次。像初始化這么重要的事兒只進行一次是有現實意義的,畢竟如果可以多次的話,我早就一米八了。

  3. 初始化之后一個Servlet就正式的進入服務狀態(tài)可以接客了,這時候就會調用service方法,接受HTTP的request,并對這個請求做一些服務項目,剪個頭發(fā)之類啊,最后再把面目全非的請求送走,不,這時候應該叫響應response。聽說每次剪頭發(fā)都像整容,可惜好久沒有剪過頭發(fā)了。

    經過第一個請求之后,再有HTTP過來的時候,Servlet會直接調用service方法為其服務,畢竟誰一輩子也不能接一個客戶初始化一次吧。

  4. 最后當服務關閉的時候,會銷毀這個對象,在銷毀前會調用destroy方法。

其他細節(jié)

會話跟蹤技術

寫到會話跟蹤要先從HTTP開始說起,在之前我們說過HTTP是無狀態(tài)的。因為其無狀態(tài)的特性,服務器不能以狀態(tài)來區(qū)分和管理請求和響應,而且一次請求響應之后就會斷開連接,所以服務器也不需要保存狀態(tài)信息,雖然這樣簡單不占資源,適用性廣,但是不利之處在于我們沒有辦法根據HTTP本身對請求做一些區(qū)分。

所以為了在保留無狀態(tài)協議這個特征的同時又解決類似記錄狀態(tài)的矛盾問題,出現了Cookie。

Cookie
cookie1.png
cookie2.png

從上圖我們知道,有幾個關鍵性的步驟是需要我們來做的:

  1. 創(chuàng)建Cookie

    //參數是cookie的標記和值,必須是英文
    Cookie cookie = new Cookie(flag,value);
    
  2. 響應信息中加上Cookie

    response.addCookie(cookie);
    
  3. 再次請求到來的時候檢查Cookie

    //獲取request中所有的cookie信息
    Cookies[] cookies = request.getCookies();
    //遍歷檢查cookie
    if(cookies != null){
      for(Cookie c : cookies){
         String name = c.getName();
        String value = c.getValue();
     }
    }
    

  1. cookie是有有效期的,一般會在瀏覽器關閉的時候自動清空

    設置cookie有效期,調用方法setMaxAge(60)

  2. cookie中的數據是不安全的,畢竟保存到本地,可以顯式查看

Session

session是服務器為每一個瀏覽器建立的私人存儲空間,其中(session作用域)可以存儲瀏覽器的屬性和一些配置信息,當瀏覽器拿到session之后(沒有更換持有的session),在不同的Servlet之間跳轉的時候,可以隨時取出放在作用域中的數據。

session.png

上圖是session的基本實現原理,我們可以看到session是通過cookie來實現的,具體的步驟是這樣的:

  1. 瀏覽器把登錄信息放入HTTP請求報文的實體部分,通常是以POST 方法把請求發(fā)送給服務器

  2. 服務器創(chuàng)建session,并將用戶信息和session進行綁定記錄在服務器,然后把處理好的session放入cookie中隨著響應發(fā)給瀏覽器。

  3. 瀏覽器收到服務器響應的帶有session信息的cookie時,會將cookie存在本地,下次請求的時候自動攜帶,服務器會通過接受其中的session對用戶進行驗證。

GET和POST的區(qū)別

從本質上來講,區(qū)別只有兩點:

  1. 參數的位置不同,GET是url后拼接參數,POST是請求報文主體傳遞參數
  2. 傳遞數據的過程不一樣,GET產生一個TCP數據包,POST產生兩個TCP數據包。

那么我們常提到的區(qū)別是從哪里來的呢?

從解釋上面的區(qū)別開始。

早期的HTTP協議只有GET方法。根據HTTP協議,服務器接收到GET請求后,會將特定資源響應給瀏覽器,GET方法是通過改寫URL實現的,在URL后面加上要傳遞的數據(格式是URL?key=value&key=value......)。所以在使用GET方法請求資源的時候,請求往往是沒有主體的。

那么問題來了,什么是主體?

所謂主體就是request的報文主體,我們知道HTTP請求的報文格式(響應雷同)是這樣的

l 起始行

l 頭信息

l 主體

GET方法的請求報文信息一般只有起始行和頭信息,如下:

<!-- 拼接后的url -->
http://localhost:8801/zhibaxm/servlet/LoginAction?username=%E5%BE%90%E9%80%9A%E8%BE%BE&pwd=123
<!-- 請求頭 -->
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Host:localhost:8801
Origin:http://localhost:8801
Referer:http://localhost:8801/zhibaxm/login.html
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36

而對于POST方法,URL不再被改寫,相關的表單數據會位于http請求的主體。如下:

<!-- url -->
http://localhost:8801/zhibaxm/servlet/LoginAction
<!-- 請求頭 -->
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Host:localhost:8801
Origin:http://localhost:8801
Referer:http://localhost:8801/zhibaxm/login.html
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
<!-- POST的主體信息 -->
username=%E5%BE%90%E9%80%9A%E8%BE%BE&pwd=123

我們知道每一個請求都是可以有三部分的:起始行,請求頭,主體,也就是說,GET和POST的區(qū)別不是語法上的,而是規(guī)范上的,簡單的說就是,你在使用POST的時候如果把參數寫在url上也是沒有問題的。

但是,我們在使用中確實有很多的不同,咋回事兒呢?這些區(qū)別并不是語法本身的不同,而是由于瀏覽器和服務器差異造成的使用上的區(qū)別,例如:大部分瀏覽器的url長度限制在2K個字節(jié),而大部分服務器最多處理64K大小的url。在使用GET方法時,如果你在報文主體寫入了數據,那么不同服務器的處理方式也是不同的,有些服務器會接受有些不會。

造成區(qū)別的原因更多不是來自語法本身,而是不同瀏覽器服務器的限制。

扯完了這些,補充一下應用上區(qū)別,畢竟遇到面試的時候,使用上的差別也是不能夠忘記的,使用上的區(qū)別如下:

GET POST
只可以接受字符串 沒有限制
不安全 相對安全
有長度限制 沒有長度限制
... ...
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 從三月份找實習到現在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時芥藍閱讀 42,887評論 11 349
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發(fā)現,斷路器,智...
    卡卡羅2017閱讀 136,699評論 19 139
  • Servlet:Sun公司制訂的一種用來擴展Web服務器功能的組件規(guī)范。當瀏覽器將請求發(fā)送給Web服務器(比如:a...
    南山伐木閱讀 635評論 0 4
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,853評論 18 399
  • 一、對號入座,我是屬于安于現狀者類型的人。學了一樣東西經歷了快速成長期后,一直就停留在平臺期,不主動追求進步和精益...
    小螃謝閱讀 450評論 1 5

友情鏈接更多精彩內容