初學Java Web(4)——Servlet學習總結

經過一段時間的學習,對于Servlet有了新的不一樣的見解,在這里做一下總結,將近來學習到的知識總結一下。


Servlet 的請求流程

  1. 瀏覽器發出請求:http://localhost:80/xxx1/xxx2 (80端口可以默認不寫,因為這是http協議默認的端口,平時我們訪問https://www.baidu.com/ 時其實訪問的是https://www.baidu.com:80/

  2. 服務器解析請求信息:

    • http:協議名稱
    • localhost:訪問的是互聯網中的哪一臺計算機
    • 80:從主機當中找到對應 80 端口的程序 這里即為 Tomcat 服務器
    • /xxx1:當前項目的上下文路徑 (即在 server.xml 中配置主機時配置的 path屬性
    • /xxx2:當前請求的資源名
  3. 解析 Tomcat 服務器根目錄下的 /config/server.xml 文件:
    <Context docBase="D:\javaPros\test\webapp" path="xxx1" />
    判斷哪一個<Context />```元素的 **path屬性** 屬性為 ```xxx1

    • 若找不到,則返回 404錯誤
    • 若找到了,則解析該<Context />元素,得到docBase屬性,獲取當前訪問 Web 項目的跟的絕對路徑:D:\javaPros\test\webapp
  4. D:\javaPros\test\webapp下的 WEB-INF 下找到 web.xml 文件
    判斷 web.xml 文件中是否有 <url-pattern> 的文本內容為 /xxx2

    • 若找不到,則返回 404錯誤
    • 若找到了,則繼續獲取該資源對應 Servlet 類的全限名稱: xxx.xxx
  5. 判斷 Servlet 實例緩存池 中是否有 xxx.xxx 的對象

Map<String,Servlet> cache = ......(Tomcat提供的);
    key:存Servlet類的全限定名稱
    value:該Servlet類的對象.
Servlet obj = cache.get("xxx.xxx");
    if(obj==null){
        //Servlet實例緩存中沒有該類的對象,第一次.
        GOTO 6:
    }else{
        //有對象,非第一次.
        GOTO 8:
    }
}
  1. 使用反射調用構造器,創建對應的對象

obj = Class.forName("xxx.xxx").newInstance();

把當前創建的 Servlet 對象,存放在緩存之中,供給下一次的使用.

cache.put("xxx.xxx",obj);

  1. 創建 ServletConfig 對象,并調用 init() 方法

obj.init(config);

  1. 創建 ServletRequest 對象和 ServletResponse 對象,并調用 service()方法

obj.service(req,resp);

  1. service() 方法中對瀏覽器作出響應操作。

Servlet 生命周期

在 Web 容器中,Servlet 主要經歷 4 個階段,如下圖:

Servlet 生命周期
  1. 加載 Servlet:當 Tomcat 第一次訪問 Servlet 的時候,Tomcat 會負責創建 Servlet 的實例。
  2. 初始化 Servlet:當 Servlet 被實例化之后,Tomcat 會調用 init() 方法來初始化這個對象。
  3. 處理服務:當瀏覽器訪問 Servlet 的時候,Servlet 會調用 service() 方法處理請求。
  4. 銷毀:Tomcat 關閉或者檢測到 Servlet 要從 Tomcat 刪除的時候,會自動調用 destroy() 方法,讓該實例所占用的資源釋放掉。一個 Servlet 如果長時間不被使用的話,也會被 Tomcat 自動銷毀。
  • 簡單總結:只要訪問 Servlet ,就會調用其對應的 service() 方法,init() 方法只會在第一次訪問 Serlvet 的時候才會被調用。

這一部分參考文章:這里是鏈接


Servlet 提供處理請求的方法

前面的文章里面提到過,廣義上,Servlet 即實現了 Servlet 接口 的類,當我們創建一個自定義類,實現 Servlet 接口 的時候,會發現有 5 個方法需要重寫,有init【初始化】,destroy【銷毀】,service【服務】,ServletConfig【Servlet配置】,getServletInfo【Serlvet信息】。

這樣做的話,我們每次都需要實現 5 個方法,太麻煩了!

我們可以直接繼承 HttpServlet 類,該類已經默認實現了 Servlet 接口中的所有方法,在編寫 Servlet 的時候,你只需要重寫你需要的方法就好了,并且該類還在原有 Servlet 接口上添加了一些與 HTTP 協議處理相關的方法,比 Servlet 接口的功能更強大。

  • Servlet 處理請求的方法一共有三種:
    ① 實現 service() 方法。
    ② 重寫 doGet()doPost() 方法,并在 doGet() 中添加一句this.doPost(req, resp);(因為無論是get或post請求提交的數據,處理方式都基本相同,下同)
    ③ 重寫 doGet()doPost() 方法,并在 doPost() 中添加一句this.doGet()(req, resp);
  • 推薦方式①。

Servlet 是單例的

為什么Servlet是單例的

瀏覽器多次對Servlet的請求,一般情況下,服務器只創建一個Servlet對象,也就是說,Servlet對象一旦創建了,就會駐留在內存中,為后續的請求做服務,直到服務器關閉。

每次訪問請求對象和響應對象都是新的

對于每次訪問請求,Servlet引擎都會創建一個新的HttpServletRequest請求對象和一個新的HttpServletResponse響應對象,然后將這兩個對象作為參數傳遞給它調用的Servlet的service()方法,service方法再根據請求方式分別調用doXXX方法。

線程安全問題

當多個用戶訪問Servlet的時候,服務器會為每個用戶創建一個線程。當多個用戶并發訪問Servlet共享資源的時候就會出現線程安全問題。

原則:
1. 如果一個變量需要多個用戶共享,則應當在訪問該變量的時候,加同步機制synchronized (對象){}
2. 如果一個變量不需要共享,直接在 doGet() 或者 doPost()定義.這樣不會存在線程安全問題

這一部分參考文章:這里是鏈接


HttpServletRequest 和 HttpServletResponse 對象

對于每次訪問請求,Servlet引擎都會創建一個新的HttpServletRequest請求對象和一個新的HttpServletResponse響應對象,即 request 和 response 對象。

既然 request 對象代表 http 請求,那么我們獲取瀏覽器提交過來的數據,就找 request 對象 即可。response 對象代表 http 響應,那么我們向瀏覽器輸出數據,找 response 對象即可。

HttpServletRequest 常用方法

  • String getContextPath():
    獲取上下文路徑,<Context path="上下文" ../>
  • String getHeader(String headName):
    根據指定的請求頭獲取對應的請求頭的值.
  • String getRequestURI():
    返回當期請求的資源名稱. 上下文路徑/資源名
  • StringBuffer getRequestURL():
    返回瀏覽器地址欄的內容
  • String getRemoteAddr():
    返回請求服務器的客戶端的IP

獲取請求參數的方法:

  • String getParameter(String name):
    根據參數名稱,獲取對應參數的值.
  • String[] getParameterValues(String name):
    根據參數名稱,獲取該參數的多個值.
  • Enumeration<String> getParameterNames():
    獲取所有請求參數的名字
  • Map<String,String[]> getParameterMap():
    返回請求參數組成的Map集合.
    key:參數名稱
    value:參數值,封裝在String數組中.

HttpServletResponse 常用方法

  • OutputStream getOutputStream():
    獲取字節輸出流:文件下載
  • Writer getWriter():
    獲取字符輸出流:輸出內容
    設置文件輸出的編碼格式和內容類型:resp.setContentType("text/html;charset=utf-8");

GET 和 POST 的區別

要知道,GET 和 POST 都是請求方式

  • GET:
    瀏覽器器地址欄:http://localhost/test.html?name=wmyskxz&sex=male
    這里提交了兩個參數,一個是name屬性值為wmyskxz,另一個是sex屬性值為male,這是一種直接的請求方式,在請求資源后面跟上 ? 符號與參數連接,其他的參數使用 & 符號連接。

  • 缺點:
    1.暴露請求信息,不安全
    2.請求信息不能超過1kb,可傳輸的信息有限,不能上傳圖片

  • POST:
    瀏覽器地址欄:http://localhost/test.html#

  • 優點:
    1.隱藏了請求信息,較安全(但仍可以通過相關工具訪問到數據)
    2.POST 方式沒有限制請求的數據大小,可以做圖片的上傳

但并不是所有的數據都需要使用 POST 請求來完成,事實上,GET 請求方式會比 POST 請求更快,當數據小并且安全性要求不是那么高的時候,GET 仍然是很好的選擇.(并且 GET 相較 POST 簡單)


請求中文亂碼的處理

Tomcat 服務器中,接受請求的時候,默認的編碼方式為 ISO-8859-1,而該編碼方式只占一個字節,不支持中文(兩個字節),所以當我們做請求的時候,會出現亂碼的問題

  • 解決方案:
    1.對亂碼使用 ISO-8859-1 解碼,轉換成byte數組,恢復為二進制
    byte[] data = name.getBytes("ISO-8859-1");
    2.對byte數組重新進行 UTF-8 編碼:
    name = new String(data,"UTF-8");
    但是這樣會出現一個問題,那就是當表單數據太多的時候,這樣反復解碼-編碼,會很繁瑣。
  • 終極解決方案:
    1.對于 POST 請求:
    設置請求的編碼方式:request.setCharacterEncoding("UTF-8");
    注意:必須在獲取第一個參數之前設置,并且該方式只對 POST 方式有效。
    2.對于 GET 請求:
    重新設置 Tomcat 的編碼方式,修改 Tomcat 的配置文件:
    Tomcat根目錄/conf/server.xml(修改端口的那一行)

Servlet 細節

  • 1.一個 Servlet 可以有多個 <url-pattern> ,可以使用多個資源名稱找到當前的 Servlet
  • 2.配置 Servlet 可以使用通配符
    *表示任意字符
    /*:可以使用
    任意的字符*訪問當前的 Servlet
    *.xxx:如 wmyskxz.wudi
  • 3.自定義的 Servlet 的 <servlet-name> 不能夠為 default ,使用它會造成項目下面的靜態資源找不到,在 Tomcat/conf/web.xml 文件中配置一個名字為default的Servlet,該Servlet在負責訪問項目下的靜態資源
    web.xml 中配置的默認項
  • 4.關于 Servlet 的初始化操作,如果初始化操作非常的耗時,那么第一個請求的用戶的用戶體驗就非常差
    解決思路:將初始化操作向前移,在服務器啟動的時候執行 Servlet 的初始化

通過注解配置 Servlet

這是 Servlet 3.0 提出的新特性,支持注解配置,這大大簡化了我們的工作。

在之前的開發工作中,我們總是去 web.xml 文件中進行配置,至少會出現8行:

web.xml 中配置 Servlet

而當一個項目中存在很多 Servlet ,那么配置文件就會變得非常臃腫,不便于后期的維護,在 Servlet 3.0 推出之后,我們可以使用注解來配置 Servlet,上面 8 行的配置可以簡化為下面的簡單的注解:

或者也可以使用屬性 value 定義訪問的 URL,只有 URL 這個屬性是必要的,name 是可以缺省的值,而默認的 value 也可以省略不寫,所以可以簡寫成:

@WebServlet("/foreServlet")

Web 組件之間的跳轉方式

1.請求轉發(forward)

又叫做直接轉發方式,客戶端和瀏覽器只發出一次請求,Servlet、HTML、JSP或其它信息資源,由第二個信息資源響應該請求,在請求對象request中,保存的對象對于每個信息資源是共享的。

比如:從 AServlet 請求轉發到 BServlet

  • 語法:
request.getRequestDispatcher(path).forward(request, response);

參數:path,要跳轉到的資源路徑:上下文路徑 / 資源路徑

  • 特點:
    1.地址欄中的地址【不會】改變
    通常看作是服務端的跳轉
    2.只有一個請求
    3.資源是共享的,也就是說在兩個 Servlet 中可以共享請求的資源
    可以通過request.setAttribute(String var1,Object var2)設置要共享的數據資源,并通過request.getAttribute(String var1);獲取傳遞的資源
    4.【可以】訪問 WEB-INF 中的資源
    WEB-INF 文件夾是 Java Web 應用的默認安全目錄,即客戶端無法直接訪問,只有服務端可以訪問的目錄。
    如果想在頁面中直接訪問其中的文件,必須通過web.xml文件對要訪問的文件進行相應映射才能訪問。
    注意:在實際的開發中,可以把不希望用戶直接訪問到(通過瀏覽器輸入地址欄)的網頁放在文件夾中通過此方式訪問。
    5.請求轉發【不能】跨域訪問
    所謂的同域,是指域名,協議,端口均相同

2.URl 重定向(redirect)

又叫做間接轉發方式(Redirect)實際是兩次HTTP請求,服務器端在響應第一次請求的時候,讓瀏覽器再向另外一個URL發出請求,從而達到轉發的目的。

比如:從AServlet重定向到BServlet

  • 語法:
response.sendRedirect(String location);

參數:location,轉發到的資源路徑

  • 特點:
    1.地址欄中的地址【會】發生改變
    通常看作是客戶端跳轉
    2.有兩個請求
    3.在兩個 Servlet 中不可以共享請求中的數據
    4.最終的響應由 BServlet 來決定,和 AServlet 沒有關系
    5.【不可以】訪問 WEB-INF 中的資源
    6.請求轉發【能】跨域訪問
    就像是在網頁中點開了新的鏈接一樣
  • 總結:URL 重定向相當于是將重定向的資源路徑,重新復制到瀏覽器地址欄中按下回車一樣,重新發送一次新的請求。

3.請求包含(include)


MVC 模式

MVC 是一種分層的設計模式 。

  • M 代表 模型(Model)
    模型是什么呢? 模型就是數據,就是dao,bean
  • V 代表 視圖(View)
    視圖是什么呢? 就是網頁, JSP,用來展示模型中的數據
  • C 代表 控制器(controller)
    控制器是什么? 控制器的作用就是把不同的數據(Model),顯示在不同的視圖(View)上。

這部分可以參考一下這里


歡迎轉載,轉載請注明出處!
簡書ID:@我沒有三顆心臟
github:wmyskxz
歡迎關注公眾微信號:wmyskxz
分享自己的學習 & 學習資料 & 生活
想要交流的朋友也可以加qq群:3382693

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,835評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,676評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,730評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,118評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,873評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,266評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,330評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,482評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,036評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,846評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,025評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,575評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,279評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,684評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,953評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,751評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,016評論 2 375

推薦閱讀更多精彩內容

  • 0 系列目錄# WEB請求處理 WEB請求處理一:瀏覽器請求發起處理 WEB請求處理二:Nginx請求反向代理 本...
    七寸知架構閱讀 14,011評論 22 190
  • 從三月份找實習到現在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發崗...
    時芥藍閱讀 42,326評論 11 349
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,723評論 18 399
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,789評論 18 139
  • 穩定的生活對孩子到底有多重要?----萬維鋼老師“精英日課”學習筆記 文/小丫Stella 前段時間寫了關于孩子教...
    田小丫_Stella閱讀 1,254評論 0 2